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,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) |
|
||||
Reference in new issue
Block a user