NetDesk 1.5.0 — source release
This commit is contained in:
commit
40318aafdd
227 files changed
+80798
No files matched your search
@@ -0,0 +1,293 @@
|
||||
# Building the NetDesk desktop app for macOS
|
||||
|
||||
This builds the **same** egui viewer/host-panel binary the Windows editions
|
||||
ship (crate `netdesk-viewer`) as a signed, notarized **universal** macOS app
|
||||
(`NetDesk.app`) and a distributable `.dmg`.
|
||||
|
||||
- One binary, two roles: the viewer window **and** the host panel, identical to
|
||||
the Windows build — only the packaging here is Mac-specific.
|
||||
- **Decode path:** on macOS the host H.264 (Annex-B) stream is decoded on the
|
||||
Apple video engine through **VideoToolbox** — `core/src/decode_vt.rs`
|
||||
(`VTDecompressionSession`, 32-bit BGRA output repacked to RGB8), gated
|
||||
`#[cfg(any(target_os = "macos", target_os = "ios"))]`. It falls back to the
|
||||
portable openh264 software decoder if the hardware path can't initialize. See
|
||||
[`cross-platform-decode.md`](./cross-platform-decode.md). No VideoToolbox-
|
||||
specific flags are needed at build time: the CoreMedia / CoreVideo /
|
||||
VideoToolbox framework `#[link]`s resolve against the active SDK.
|
||||
|
||||
> **Where this runs:** on the Mac (the M4), **not** the Windows dev box. Cross-
|
||||
> compiling a macOS `.app` from Windows is not supported — codesign, notarytool,
|
||||
> iconutil, lipo and hdiutil are all macOS-only tools.
|
||||
|
||||
The script is [`packaging/build-macos.sh`](../packaging/build-macos.sh). All
|
||||
outputs land in `packaging/dist/`.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR — the Mac build command
|
||||
|
||||
Once the one-time Apple Developer setup below is done (Developer ID cert in the
|
||||
keychain + a stored `notarytool` profile named `netdesk`), the whole signed +
|
||||
notarized build is:
|
||||
|
||||
```bash
|
||||
# on the Mac, from the repo root:
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
bash packaging/build-macos.sh --notary-profile netdesk
|
||||
```
|
||||
|
||||
That produces, in `packaging/dist/`:
|
||||
|
||||
| Artifact | What it is |
|
||||
|----------------------------------------|---------------------------------------------|
|
||||
| `NetDesk.app` | signed + notarized + **stapled** universal app |
|
||||
| `NetDesk-macOS-universal.dmg` | signed + notarized + stapled disk image (ship this) |
|
||||
|
||||
Useful flags: `--skip-build` (reuse the per-target binaries), `--no-sign`
|
||||
(local unsigned test build), `--no-notarize` (sign but skip the Apple round-
|
||||
trip), `--identity "…"`, `--icon <png>`, `--version <x.y.z>`, `--entitlements
|
||||
<plist>`. Run `bash packaging/build-macos.sh --help` for the full list.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites (on the Mac)
|
||||
|
||||
1. **Xcode command-line tools** (gives `clang`, the SDKs, `lipo`, `iconutil`,
|
||||
`sips`, `hdiutil`, `codesign`, `xcrun`):
|
||||
|
||||
```bash
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
A full Xcode install from the App Store also works.
|
||||
|
||||
2. **Rust** via rustup. The script adds the two Apple-silicon/Intel std targets
|
||||
for you, but you can pre-add them:
|
||||
|
||||
```bash
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
rustup target add aarch64-apple-darwin x86_64-apple-darwin
|
||||
```
|
||||
|
||||
3. An **Apple Developer Program** membership (needed only for signing +
|
||||
notarization — a `--no-sign` build needs none). Set that up once, below.
|
||||
|
||||
---
|
||||
|
||||
## One-time Apple Developer setup
|
||||
|
||||
You need a **Developer ID Application** certificate (this is the identity that
|
||||
lets an app run on *any* Mac after notarization — distinct from the "Apple
|
||||
Development" / "Apple Distribution" / Mac App Store certs) and a way for
|
||||
`notarytool` to authenticate.
|
||||
|
||||
### 1. Enrol in the Apple Developer Program
|
||||
|
||||
<https://developer.apple.com/programs/> — \$99/yr. You must be the **Account
|
||||
Holder** (or have the Admin role) to create a Developer ID certificate.
|
||||
|
||||
### 2. Create the "Developer ID Application" certificate
|
||||
|
||||
Easiest, via Xcode:
|
||||
|
||||
1. Xcode → **Settings… → Accounts**, sign in with the Apple ID on the team.
|
||||
2. Select the team → **Manage Certificates…**
|
||||
3. Click **+** → **Developer ID Application**.
|
||||
4. Xcode creates the private key + cert and installs both into your **login
|
||||
keychain**. (Back up the private key — it cannot be re-downloaded.)
|
||||
|
||||
Or manually at <https://developer.apple.com/account/resources/certificates> →
|
||||
**+** → *Developer ID → Developer ID Application*, upload a CSR made with
|
||||
**Keychain Access → Certificate Assistant → Request a Certificate from a
|
||||
Certificate Authority**, then double-click the downloaded `.cer` to install it.
|
||||
|
||||
Verify it is present and usable for signing:
|
||||
|
||||
```bash
|
||||
security find-identity -v -p codesigning
|
||||
# look for a line like:
|
||||
# 1) ABCD… "Developer ID Application: Akronlogic LLC (TEAMID1234)"
|
||||
```
|
||||
|
||||
The script auto-detects this identity; override with `--identity "Developer ID
|
||||
Application: Akronlogic LLC (TEAMID1234)"` if you have more than one.
|
||||
|
||||
### 3. Find your Team ID
|
||||
|
||||
<https://developer.apple.com/account> → **Membership details** → *Team ID* (a
|
||||
10-character string, also shown in the parentheses of the identity name above).
|
||||
|
||||
### 4. Create credentials for notarytool
|
||||
|
||||
Two supported options — pick one:
|
||||
|
||||
**A. App-specific password (simplest).** At <https://appleid.apple.com> →
|
||||
*Sign-In and Security → App-Specific Passwords* → **+**, label it e.g.
|
||||
`netdesk-notarytool`. Then store it once in the keychain as a named profile:
|
||||
|
||||
```bash
|
||||
xcrun notarytool store-credentials netdesk \
|
||||
--apple-id "you@akronlogic.com" \
|
||||
--team-id "TEAMID1234" \
|
||||
--password "abcd-efgh-ijkl-mnop" # the app-specific password
|
||||
```
|
||||
|
||||
`netdesk` is the profile name you pass to `--notary-profile netdesk`.
|
||||
|
||||
**B. App Store Connect API key.** Create a key at *App Store Connect → Users and
|
||||
Access → Integrations → App Store Connect API* (role: *Developer*), download the
|
||||
`AuthKey_XXXX.p8`, and store it:
|
||||
|
||||
```bash
|
||||
xcrun notarytool store-credentials netdesk \
|
||||
--key "/path/AuthKey_XXXXXXXX.p8" \
|
||||
--key-id "XXXXXXXXXX" \
|
||||
--issuer "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
|
||||
```
|
||||
|
||||
> Instead of a stored profile you can pass credentials inline each run:
|
||||
> `--apple-id you@akronlogic.com --team-id TEAMID1234` **plus** the app-specific
|
||||
> password in the environment: `export NETDESK_NOTARY_PASSWORD='abcd-efgh-…'`.
|
||||
|
||||
---
|
||||
|
||||
## What the script does (step by step)
|
||||
|
||||
`packaging/build-macos.sh`:
|
||||
|
||||
1. **rustup target add** `aarch64-apple-darwin` `x86_64-apple-darwin`.
|
||||
2. **cargo build --release -p netdesk-viewer** once per target — producing
|
||||
`target/aarch64-apple-darwin/release/netdesk-viewer` and the `x86_64` one.
|
||||
(Cross-building the Intel slice on an Apple-silicon Mac uses the same SDK and
|
||||
needs no extra tooling.)
|
||||
3. **lipo -create** the two into one universal Mach-O at
|
||||
`NetDesk.app/Contents/MacOS/NetDesk` (`lipo -info` prints `arm64 x86_64`).
|
||||
4. **iconutil** builds `NetDesk.icns` from the largest PNG master it finds
|
||||
(`assets/icon-1024.png` → `icon-512.png` → `icon.png`, or `--icon <png>`):
|
||||
`sips` resizes the master into a complete `.iconset` (16→1024 px, @1x/@2x),
|
||||
then `iconutil -c icns` packs it into `Contents/Resources/NetDesk.icns`.
|
||||
5. **Assembles `NetDesk.app`** — writes `Contents/Info.plist` with bundle id
|
||||
**`com.akronlogic.netdesk`**, `CFBundleVersion` / `CFBundleShortVersionString`
|
||||
= the workspace version (read from `Cargo.toml`, currently **0.1.0**),
|
||||
`CFBundleExecutable`/`CFBundleIconFile` = `NetDesk`, `LSMinimumSystemVersion`
|
||||
11.0, `NSHighResolutionCapable`, plus a `PkgInfo` (`APPL????`).
|
||||
6. **codesign** the executable and the bundle with the Developer ID Application
|
||||
identity, **`--options runtime`** (hardened runtime, required to notarize) and
|
||||
**`--timestamp`** (secure timestamp), then `codesign --verify --deep --strict`.
|
||||
7. **Notarize + staple the `.app`**: `ditto -c -k --keepParent` it into a zip,
|
||||
`xcrun notarytool submit … --wait`, then `xcrun stapler staple NetDesk.app`
|
||||
so the ticket travels with the app offline. (Skip with `--no-staple-app`.)
|
||||
8. **Build the `.dmg`** (`hdiutil create`, UDZO, with an `/Applications`
|
||||
symlink for drag-install), **sign** it, **notarize** it
|
||||
(`notarytool submit … --wait`), and **staple** it.
|
||||
|
||||
If no Developer ID identity is found (or `--no-sign`), it still produces an
|
||||
**unsigned** `.app` + `.dmg` and tells you so — handy for a local smoke test.
|
||||
If signing works but no notarization credentials are present, it signs and
|
||||
prints exactly how to add them, like the Windows installer script does when
|
||||
NSIS is missing.
|
||||
|
||||
---
|
||||
|
||||
## Exact commands (equivalent to what the script runs)
|
||||
|
||||
If you want to drive it by hand, this is the full sequence (`VERSION=0.1.0`,
|
||||
`ID="Developer ID Application: Akronlogic LLC (TEAMID1234)"`):
|
||||
|
||||
```bash
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
|
||||
# 1-2. targets + release builds
|
||||
rustup target add aarch64-apple-darwin x86_64-apple-darwin
|
||||
cargo build --release -p netdesk-viewer --target aarch64-apple-darwin
|
||||
cargo build --release -p netdesk-viewer --target x86_64-apple-darwin
|
||||
|
||||
# 3. universal binary
|
||||
mkdir -p packaging/dist/NetDesk.app/Contents/MacOS packaging/dist/NetDesk.app/Contents/Resources
|
||||
lipo -create -output packaging/dist/NetDesk.app/Contents/MacOS/NetDesk \
|
||||
target/aarch64-apple-darwin/release/netdesk-viewer \
|
||||
target/x86_64-apple-darwin/release/netdesk-viewer
|
||||
|
||||
# 4. icon (ICONSET fully populated 16..1024 as in the script)
|
||||
iconutil -c icns NetDesk.iconset -o packaging/dist/NetDesk.app/Contents/Resources/NetDesk.icns
|
||||
|
||||
# 5. Info.plist (the script writes com.akronlogic.netdesk + version 0.1.0)
|
||||
|
||||
# 6. sign (hardened runtime + timestamp)
|
||||
codesign --force --timestamp --options runtime --sign "$ID" packaging/dist/NetDesk.app/Contents/MacOS/NetDesk
|
||||
codesign --force --timestamp --options runtime --sign "$ID" packaging/dist/NetDesk.app
|
||||
codesign --verify --deep --strict --verbose=2 packaging/dist/NetDesk.app
|
||||
|
||||
# 7. notarize + staple the app
|
||||
ditto -c -k --keepParent packaging/dist/NetDesk.app packaging/dist/NetDesk.zip
|
||||
xcrun notarytool submit packaging/dist/NetDesk.zip --keychain-profile netdesk --wait
|
||||
xcrun stapler staple packaging/dist/NetDesk.app
|
||||
|
||||
# 8. dmg -> sign -> notarize -> staple
|
||||
hdiutil create -volname NetDesk -srcfolder <stage-with-app+Applications-symlink> \
|
||||
-fs HFS+ -format UDZO -ov packaging/dist/NetDesk-macOS-universal.dmg
|
||||
codesign --force --timestamp --sign "$ID" packaging/dist/NetDesk-macOS-universal.dmg
|
||||
xcrun notarytool submit packaging/dist/NetDesk-macOS-universal.dmg --keychain-profile netdesk --wait
|
||||
xcrun stapler staple packaging/dist/NetDesk-macOS-universal.dmg
|
||||
```
|
||||
|
||||
The script wraps all of this (with the full `.iconset` generation, the plist,
|
||||
auto-detection, and graceful fallbacks) — prefer it over the manual steps.
|
||||
|
||||
---
|
||||
|
||||
## Verify a finished build
|
||||
|
||||
```bash
|
||||
# signature valid + hardened runtime + Developer-ID authority
|
||||
codesign --verify --deep --strict --verbose=2 packaging/dist/NetDesk.app
|
||||
codesign -dv --verbose=4 packaging/dist/NetDesk.app 2>&1 | grep -E 'Authority|Timestamp|flags|Identifier'
|
||||
|
||||
# Gatekeeper will accept it (Developer ID + notarized)
|
||||
spctl -a -vvv --type exec packaging/dist/NetDesk.app
|
||||
|
||||
# notarization ticket is stapled (works offline)
|
||||
xcrun stapler validate packaging/dist/NetDesk.app
|
||||
xcrun stapler validate packaging/dist/NetDesk-macOS-universal.dmg
|
||||
```
|
||||
|
||||
`spctl` should print `source=Notarized Developer ID` and `accepted`.
|
||||
|
||||
---
|
||||
|
||||
## Runtime permissions (host mode)
|
||||
|
||||
Signing/notarization are **not** the macOS capture permissions. When the binary
|
||||
runs as the **host** and first tries to capture the screen or inject input,
|
||||
macOS prompts the user (TCC) to grant, under **System Settings → Privacy &
|
||||
Security**:
|
||||
|
||||
- **Screen Recording** — to capture the remote screen.
|
||||
- **Accessibility** — to inject mouse/keyboard input (CGEvent).
|
||||
|
||||
These are user-granted at runtime and are **not** code-signing entitlements, so
|
||||
the default build needs no entitlements file. (If a future host feature drives
|
||||
*other* apps via Apple Events, add an entitlements plist with the matching keys
|
||||
and pass it via `--entitlements`.)
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`no identity found` / unsigned output** — the Developer ID Application cert
|
||||
(and its private key) must be in the login keychain of the user running the
|
||||
build; confirm with `security find-identity -v -p codesigning`.
|
||||
- **Notarization `Invalid` / rejected** — fetch the log:
|
||||
`xcrun notarytool log <submission-id> --keychain-profile netdesk`. Almost
|
||||
always a missing `--options runtime` (hardened runtime) or a missing secure
|
||||
`--timestamp`; the script sets both.
|
||||
- **`The binary is not signed with a valid Developer ID certificate`** — an
|
||||
*Apple Development* cert was used instead of *Developer ID Application*; only
|
||||
the latter notarizes for distribution outside the App Store.
|
||||
- **openh264 fails to cross-compile the x86_64 slice** — it builds C++ via the
|
||||
`cc` crate; the Xcode CLT clang handles `-arch x86_64` on an arm Mac, so a
|
||||
full `xcode-select --install` (or Xcode) is enough. If it still fails, build
|
||||
only the native slice with `--target aarch64-apple-darwin` and drop the lipo
|
||||
step (the app is then arm64-only).
|
||||
- **Icon looks soft** — add a 1024×1024 `assets/icon-1024.png` master (the repo
|
||||
currently ships 256 and 512); the script prefers the largest it finds.
|
||||
Reference in new issue
Block a user