NetDesk 1.5.0 — source release

This commit is contained in:
NetDesk committed 2026-10-18 02:02:46 +00:00
commit 40318aafdd
227 files changed
+80798

No files matched your search

+288
View File
@@ -0,0 +1,288 @@
# NetDesk — iOS build (`.ipa`)
How to build the signed NetDesk iOS app — the Flutter UI on top of the compiled
Rust `netdesk-core` engine — and ship it to TestFlight / the App Store.
> **This only builds on a Mac.** iOS toolchains (Xcode, the iOS SDKs,
> `xcodebuild`, code signing) exist on macOS only. Nothing here can run on the
> Windows dev box — Windows is used to *author* these scripts, the Mac runs
> them. Everything below assumes macOS + Xcode.
---
## 1. What gets built
```
core crate (netdesk-core, lib netdesk_core)
│ cargo build --release --target aarch64-apple-ios → libnetdesk_core.a (device)
│ cargo build --release --target aarch64-apple-ios-sim → libnetdesk_core.a (simulator)
▼
NetDeskCore.xcframework (xcodebuild -create-xcframework, both slices)
│ vendored via ui/ios/netdesk_core.podspec + pod 'netdesk_core' in the Podfile
▼
Flutter iOS Runner ── flutter build ipa ──► ui/build/ios/ipa/netdesk.ipa
```
The Rust static library is the FFI surface the Flutter UI binds to. Today that
is the workspace **`core`** crate (`crate-type = ["lib","staticlib","cdylib"]`,
lib name `netdesk_core` → `libnetdesk_core.a`). When the Phase-3
`flutter_rust_bridge` wrapper crate lands under a different package name (e.g.
`netdesk-frb`), build it with the same script by overriding two variables:
```bash
CORE_CRATE=netdesk-frb LIB_NAME=netdesk_frb packaging/build-ios.sh --team <TEAM_ID>
```
---
## 2. Prerequisites
### 2.1 Apple Developer Program — **$99/year**
A paid **Apple Developer Program** membership (<https://developer.apple.com/programs/>,
US$99/yr) is required to:
- create a **distribution signing certificate**,
- register an **App ID** (bundle identifier) and a **provisioning profile**,
- upload to **App Store Connect / TestFlight**.
The free personal team can only sideload to your own device for 7 days — not
enough to ship. Enroll first; enrollment can take a day or two to clear.
### 2.2 Signing certificate + provisioning profile
You need, inside your developer account:
| Thing | Where | Notes |
|-------|-------|-------|
| **Team ID** | developer.apple.com → Membership | 10 chars, e.g. `ABCDE12345`. You pass this to the script. |
| **App ID / bundle id** | Certificates, IDs & Profiles → Identifiers | Must match the app's `PRODUCT_BUNDLE_IDENTIFIER` (default `space.netdesk.netdesk`, set via `--org`). |
| **Distribution certificate** | Certificates, IDs & Profiles → Certificates → *Apple Distribution* | One per team; Xcode can create it for you. |
| **Provisioning profile** | Certificates, IDs & Profiles → Profiles → *App Store* (or Ad Hoc) | Ties the App ID + certificate + devices. |
**Easiest path — automatic signing.** Open the project once in Xcode, sign in
with your Apple ID, tick *Automatically manage signing*, pick your Team. Xcode
creates the certificate + profile for you and the command-line build reuses
them. `build-ios.sh` writes `DEVELOPMENT_TEAM` + `CODE_SIGN_STYLE = Automatic`
into `ui/ios/Flutter/{Release,Debug}.xcconfig`, so after that one-time Xcode
sign-in the whole build is non-interactive.
**Manual signing** (CI, locked-down teams): download the distribution
certificate (`.p12`) and the provisioning profile (`.mobileprovision`), install
both into the login keychain / `~/Library/MobileDevice/Provisioning Profiles/`,
then set `signingStyle` to `manual` and add a `provisioningProfiles` dict in
`ui/ios/ExportOptions.plist`.
### 2.3 Toolchains on the Mac
```bash
# Xcode + command line tools
xcode-select --install # or install full Xcode from the App Store
sudo xcode-select -s /Applications/Xcode.app
# Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
# Flutter SDK (>= 3.27, per ui/pubspec.yaml) — add its bin/ to PATH
# https://docs.flutter.dev/get-started/install/macos
flutter doctor
# CocoaPods (Flutter will also install pods during the build)
sudo gem install cocoapods
```
> **PATH note.** On Windows the project builds with
> `export PATH="/c/mingw-netdesk/mingw64/bin:$HOME/.cargo/bin:/c/dev/flutter/bin:$PATH"`.
> On the **Mac** that line does not apply — just make sure `cargo`, `rustup`,
> `flutter` and `xcrun` are on PATH (`source $HOME/.cargo/env`, Flutter's
> `bin/` in your shell profile).
---
## 3. Generate the Flutter iOS project (one time)
`ui/` currently has `lib/` + `pubspec.yaml` but **no `ios/` folder** — it was
never generated (it's platform scaffolding, not source). Create it on the Mac:
```bash
cd ui
flutter create --org space.netdesk --project-name netdesk --platforms=ios .
```
This adds `ui/ios/` (the `Runner` Xcode project, `Runner.xcworkspace`,
`Info.plist`, launch assets, the Flutter xcconfig layer) without touching your
`lib/` Dart code. The bundle identifier becomes `<org>.netdesk`, i.e.
`space.netdesk.netdesk` — change `--org` to use your own (e.g.
`--org com.akronlogic` → `com.akronlogic.netdesk`), and register that exact id
as the App ID in your developer account.
> On the Windows box the equivalent invocation (for reference only — it does not
> produce a buildable iOS app on Windows) is:
> `C:\dev\flutter\bin\flutter.bat create --platforms=ios .`
**`build-ios.sh` runs this step for you** if `ui/ios/` does not exist, so you
can skip straight to §5. Run it by hand only if you want to pick the `--org`
yourself before the first build.
---
## 4. The VideoToolbox decode path (why the frameworks matter)
NetDesk's iOS H.264 decode is **hardware** via **VideoToolbox**, implemented in
[`core/src/decode_vt.rs`](../core/src/decode_vt.rs) and gated
`#[cfg(any(target_os = "macos", target_os = "ios"))]`. It feeds Annex-B →
AVCC-repacked access units into a `VTDecompressionSession`, builds the
`CMVideoFormatDescription` from the first keyframe's SPS/PPS, and asks for
32-bit BGRA output (VideoToolbox does the YUV→RGB on the GPU); openh264 is the
software fallback if the session can't start.
That module links three Apple system frameworks directly with
`#[link(kind = "framework")]`:
| Framework | Used for |
|-----------|----------|
| **VideoToolbox** | `VTDecompressionSession*` (the decoder itself) |
| **CoreMedia** | `CMVideoFormatDescription` / `CMSampleBuffer` / `CMBlockBuffer` |
| **CoreVideo** | `CVPixelBuffer*` (the decoded BGRA surface) |
| **CoreFoundation** | `CFDictionary`/`CFString`/`CFRelease` (via `core-foundation-sys`, for the pixel-buffer attributes) |
A **static** Rust library records those `#[link]` directives in its metadata but
does **not** pull the frameworks into the final app link. So the podspec
(`ui/ios/netdesk_core.podspec`) names them explicitly:
```ruby
s.frameworks = 'VideoToolbox', 'CoreMedia', 'CoreVideo', 'CoreFoundation'
```
If you ever see link errors like `Undefined symbol: _VTDecompressionSessionCreate`
or `_CMVideoFormatDescriptionCreateFromH264ParameterSets`, a framework is
missing from that line. At runtime, the log line
`decode: VideoToolbox H.264 (hardware)` confirms the hardware path was selected.
---
## 5. Build the `.ipa` — the exact commands
### One command (recommended)
```bash
# from the repo root, on the Mac:
packaging/build-ios.sh --team ABCDE12345
```
Replace `ABCDE12345` with your 10-character Apple **Team ID**. That script does
every step in §6 and prints the path to the finished `.ipa`. Useful variants:
```bash
packaging/build-ios.sh --team ABCDE12345 --method app-store # default: App Store / TestFlight
packaging/build-ios.sh --team ABCDE12345 --method ad-hoc # ad-hoc distribution
packaging/build-ios.sh --team ABCDE12345 --method development # dev devices
packaging/build-ios.sh --team ABCDE12345 --org com.akronlogic # bundle id com.akronlogic.netdesk (first run only)
packaging/build-ios.sh --skip-ipa # build NetDeskCore.xcframework only, no signing needed
```
Output:
- `ui/build/ios/ipa/netdesk.ipa` — the signed app
- `packaging/dist/ios/NetDeskCore.xcframework` — the Rust core (also staged into `ui/ios/`)
### The same steps by hand
If you'd rather run it step by step (this is exactly what the script does):
```bash
# 0. Rust iOS targets
rustup target add aarch64-apple-ios aarch64-apple-ios-sim
# 1. Build the Rust core static lib for device + simulator
export IPHONEOS_DEPLOYMENT_TARGET=13.0
cargo build --release -p netdesk-core --target aarch64-apple-ios
cargo build --release -p netdesk-core --target aarch64-apple-ios-sim
# 2. Assemble the xcframework (delete any stale one first)
rm -rf packaging/dist/ios/NetDeskCore.xcframework
xcodebuild -create-xcframework \
-library target/aarch64-apple-ios/release/libnetdesk_core.a \
-library target/aarch64-apple-ios-sim/release/libnetdesk_core.a \
-output packaging/dist/ios/NetDeskCore.xcframework
# 3. Generate ui/ios if needed, then wire the xcframework in
cd ui
flutter create --org space.netdesk --project-name netdesk --platforms=ios . # only if ui/ios is missing
flutter pub get
cp -R ../packaging/dist/ios/NetDeskCore.xcframework ios/
cp ../packaging/ios/netdesk_core.podspec ios/netdesk_core.podspec
# ... add `pod 'netdesk_core', :path => '.'` to ios/Podfile (Runner target),
# ... add DEVELOPMENT_TEAM + CODE_SIGN_STYLE=Automatic to ios/Flutter/*.xcconfig,
# ... write ios/ExportOptions.plist with your teamID + method.
cd ios && pod install && cd ..
# 4. Build + sign the ipa
flutter build ipa --release --export-options-plist=ios/ExportOptions.plist
# → ui/build/ios/ipa/netdesk.ipa
```
### Ship it
```bash
# TestFlight / App Store (App Store Connect API key):
xcrun altool --upload-app -f ui/build/ios/ipa/netdesk.ipa -t ios \
--apiKey <KEY_ID> --apiIssuer <ISSUER_ID>
```
Or open `ui/build/ios/archive/Runner.xcarchive` in **Xcode → Window →
Organizer → Distribute App** and follow the GUI.
---
## 6. What `build-ios.sh` automates (summary)
1. **Preflight** — macOS, Xcode, `rustup`/`cargo`, `flutter`, and a Team ID (unless `--skip-ipa`).
2. **`rustup target add`** `aarch64-apple-ios aarch64-apple-ios-sim`.
3. **`cargo build --release`** the core staticlib for both targets (`IPHONEOS_DEPLOYMENT_TARGET=13.0`).
4. **`xcodebuild -create-xcframework`** → `NetDeskCore.xcframework`.
5. **`flutter create`** `ui/ios` if missing, copy the xcframework + podspec in, inject the pod into the Podfile, set the signing team in the Flutter xcconfigs, write `ExportOptions.plist`, `pod install`.
6. **`flutter build ipa`** with your team and export method.
---
## 7. Gotchas
- **Apple-silicon vs Intel Mac.** The simulator slice defaults to
`aarch64-apple-ios-sim` (Apple silicon). On an Intel Mac build the Intel
simulator slice instead: `SIM_TARGET=x86_64-apple-ios packaging/build-ios.sh …`
(and `rustup target add x86_64-apple-ios`). The device slice is always
`aarch64-apple-ios`.
- **First build compiles openh264 from source** (the software-decode fallback).
That needs the Xcode clang/C++ toolchain (present with Xcode) — the first
`cargo build` is slow; later ones are cached.
- **Deployment target.** Keep `IPHONEOS_DEPLOYMENT_TARGET`, the podspec
`platform :ios`, and the Runner's min iOS in sync (all `13.0` here). Mismatches
cause CocoaPods warnings or link errors.
- **Bundle id must match the App ID.** The provisioning profile is tied to a
specific bundle id; if `--org` doesn't match a registered App ID, signing
fails. Register the id in your developer account first.
- **Phase-3 FFI.** This build links the Rust core but the Flutter UI does not
*call* it yet (the Dart bindings are Phase 3: uncomment `flutter_rust_bridge`
+ `ffi` in `ui/pubspec.yaml`, add `core/src/ffi.rs`, generate the header with
`cbindgen`, add `-headers` to the `xcodebuild -create-xcframework` call, and
run `flutter_rust_bridge_codegen generate`). Until then the archive may be
dead-stripped out of the app — harmless; the signed `.ipa` still builds. See
the commented `-force_load` block in `netdesk_core.podspec` to force a link
test before Phase 3.
- **`xcodebuild -create-xcframework` refuses to overwrite** an existing output —
the script `rm -rf`s the old xcframework first; do the same by hand.
---
## 8. Files
| Path | Role |
|------|------|
| `packaging/build-ios.sh` | the end-to-end Mac build script |
| `packaging/ios/netdesk_core.podspec` | CocoaPods spec vendoring the xcframework + system frameworks (copied to `ui/ios/`) |
| `packaging/ios/Podfile` | Flutter iOS Podfile template with the `netdesk_core` pod (used if `ui/ios/Podfile` is absent) |
| `packaging/dist/ios/NetDeskCore.xcframework` | build output — the compiled Rust core |
| `core/src/decode_vt.rs` | the VideoToolbox hardware-decode implementation |
| `docs/cross-platform-decode.md` | the per-platform decode design (VideoToolbox section) |