NetDesk 1.5.0 — source release

This commit is contained in:
NetDesk committed 2026-10-18 01:35:59 +02:00
commit ec4955682f
227 files changed
+80669

No files matched your search

+180
View File
@@ -0,0 +1,180 @@
# Building NetDesk for Android
NetDesk's Android app is a Flutter UI (`ui/`) bound, through
[flutter_rust_bridge](https://cjycode.com/flutter_rust_bridge/) (FRB v2), to a
compiled Rust library. The Rust FFI layer is the **`netdesk-frb`** crate
(`frb/`), a `cdylib` that statically links **`netdesk-core`** (signaling, E2E
crypto, transport, H.264 decode). On Android the library ships inside the
APK/AAB as `lib/<abi>/libnetdesk_frb.so` and the Dart side `dlopen`s it (the FRB
loader looks for the stem `netdesk_frb`).
```
netdesk-frb (+ netdesk-core) --cargo-ndk--> ui/android/app/src/main/jniLibs/<abi>/libnetdesk_frb.so
Flutter (ui/) --gradle-----> release .apk / split .apk / .aab (signed)
```
---
## The one command
From the repo root (`netdesk-native/`), in a shell whose `PATH` contains the
MinGW tools, cargo, and Flutter:
```powershell
powershell -ExecutionPolicy Bypass -File packaging\build-android.ps1
```
That single command:
1. verifies / auto-provisions the toolchain (cargo-ndk, the rustup Android
targets),
2. detects the Android NDK at `C:\dev\android-ndk`,
3. compiles `netdesk-frb` for **arm64-v8a, armeabi-v7a, x86_64** with cargo-ndk
and drops `libnetdesk_frb.so` straight into
`ui/android/app/src/main/jniLibs/<abi>/`,
4. builds the release **fat APK**, the **per-ABI split APKs**, and the Play
**App Bundle (.aab)**.
Useful switches:
| Switch | Effect |
| --- | --- |
| `-Target apk\|split\|aab\|rust\|all` | Build only that deliverable (default `all`; `rust` = just the `.so`). |
| `-SkipRust` | Reuse the `.so` already in `jniLibs`, build Flutter only. |
| `-Abis arm64-v8a` | Restrict the ABIs (default all three). |
| `-GenerateKeystore` | Create the release keystore + `key.properties` first (see below). |
| `-MinSdk 21` | Android API the `.so` links against (must be `<=` Flutter `minSdk`). |
| `-NdkHome <path>` | Override the NDK location (default `C:\dev\android-ndk`). |
---
## Toolchain
| Component | Version / location used here |
| --- | --- |
| Rust | stable (cargo 1.99) on `PATH` |
| rustup targets | `aarch64-linux-android`, `armv7-linux-androideabi`, `x86_64-linux-android` |
| cargo-ndk | 4.1.2 (`cargo install cargo-ndk`) |
| Android NDK | r26d (`26.3.11579264`) at `C:\dev\android-ndk` (`ANDROID_NDK_HOME`) |
| Android SDK | `%LOCALAPPDATA%\Android\Sdk` |
| Flutter | `C:\dev\flutter\bin\flutter.bat` |
| JDK (keytool + Gradle) | Android Studio JBR (auto-detected) |
| nasm | on `PATH` (needed by `openh264` for the x86_64 ABI) |
One-time setup (the build script also does the first three automatically):
```powershell
rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android
cargo install cargo-ndk
# NDK: unzip the Android NDK r26+ to C:\dev\android-ndk (set ANDROID_NDK_HOME)
```
Recommended `PATH` (Git Bash form):
```bash
export PATH="/c/mingw-netdesk/mingw64/bin:$HOME/.cargo/bin:/c/dev/flutter/bin:$PATH"
```
### What cargo-ndk runs
The Rust step is exactly:
```
cargo ndk -t arm64-v8a -t armeabi-v7a -t x86_64 \
-o ui/android/app/src/main/jniLibs --platform 21 \
build --release --package netdesk-frb --lib
```
cargo-ndk sets the per-ABI clang/linker from the NDK, and the `-o` flag copies
each produced `libnetdesk_frb.so` into `jniLibs/<abi>/`. The `.so` are build
artifacts (git-ignored) and are regenerated on every run.
---
## Release signing
Signing credentials live in `ui/android/key.properties`, which is **git-ignored**
(so are `*.keystore` / `*.jks`). A committable template is
`ui/android/key.properties.example`.
`app/build.gradle.kts` loads `key.properties` when present and signs the release
build with it; when it is absent the release build falls back to **debug**
signing so `flutter run --release` still works during development.
Create the upload keystore once (the password is read from the environment and
is **never** written into a committed file):
```powershell
$env:NETDESK_KEYSTORE_PASSWORD = '<your-strong-password>'
powershell -ExecutionPolicy Bypass -File packaging\build-android.ps1 -GenerateKeystore
```
This writes:
* `ui/android/app/netdesk-release.keystore` - RSA 4096, alias `netdesk`, 10000-day validity,
* `ui/android/key.properties` - with the alias, store file, and the password you
supplied (local only; keep it out of version control).
> Back up the keystore and remember the password. If you lose either you can no
> longer push updates to an app already published under that key (unless it uses
> Play App Signing with a separate upload key you can reset).
---
## Outputs
After a full build:
| Deliverable | Path (under `ui/`) |
| --- | --- |
| Fat APK (all ABIs) | `build/app/outputs/flutter-apk/app-release.apk` |
| Split APKs (per ABI) | `build/app/outputs/flutter-apk/app-arm64-v8a-release.apk`, `-armeabi-v7a-`, `-x86_64-` |
| Play App Bundle | `build/app/outputs/bundle/release/app-release.aab` |
The fat APK is convenient for side-loading / direct download; the split APKs are
smaller per device; the `.aab` is what Google Play requires.
---
## Publishing to Google Play (AAB)
1. Produce the signed bundle:
```powershell
powershell -ExecutionPolicy Bypass -File packaging\build-android.ps1 -Target aab
```
(or run the default `all` target). The bundle is
`ui/build/app/outputs/bundle/release/app-release.aab`.
2. In the [Play Console](https://play.google.com/console), create the app, then
upload the `.aab` under a release track (internal testing first).
3. Enrol in **Play App Signing** (recommended). Google then holds the *app
signing key*; the keystore above becomes your *upload key*. If the upload key
is ever compromised you can ask Google to reset it - which is why App Signing
is preferred over shipping the raw signing key.
4. `versionCode` / `versionName` come from `ui/pubspec.yaml`
(`version: x.y.z+build`). Bump the `+build` number for every Play upload - the
Console rejects a duplicate `versionCode`.
---
## Troubleshooting
* **"Android NDK not found"** - the script could not find a complete NDK at
`C:\dev\android-ndk` (it checks for `source.properties` +
`toolchains\llvm\prebuilt`). Finish extracting the NDK, set `ANDROID_NDK_HOME`,
or pass `-NdkHome <path>`. Use `-SkipRust` to build only the Flutter layer
against an already-built `.so`.
* **x86_64 ABI fails in `openh264`** - that ABI needs `nasm` on `PATH`. arm64-v8a
and armeabi-v7a do not. Drop x86_64 with `-Abis arm64-v8a,armeabi-v7a` if you
only ship to real devices.
* **Gradle wants to download an NDK** - `app/build.gradle.kts` points AGP at
`ANDROID_NDK_HOME` when it is set, so the prebuilt (already stripped) `.so` are
packaged without a second NDK download. Make sure the env var is set (the build
script sets it).
* **`UnsatisfiedLinkError: libnetdesk_frb.so`** at runtime - the `.so` for the
device's ABI is missing from `jniLibs`. Re-run the Rust step (`-Target rust`)
for that ABI, or confirm the FRB loader stem is still `netdesk_frb`.