diff --git a/docs/android-dev.md b/docs/android-dev.md new file mode 100644 index 0000000..90212f5 --- /dev/null +++ b/docs/android-dev.md @@ -0,0 +1,117 @@ +# Running the Android client locally + +The Android app is the same Vue frontend and Rust core as the desktop, built by +Tauri v2 mobile. This sheet is the local setup; CI's copy of it is the +`ci-tauri-android` image (see `ci-requirements.md`). + +**Open this directory in Android Studio:** + +``` +desktop/src-tauri/gen/android +``` + +Two things must be true first, and both fail confusingly if they aren't. + +## 1. Gradle must run on JDK 17 + +Android Studio defaults to its own bundled JDK, which is currently 25. That +produces: + +> Incompatible Gradle JVM version — The project's Gradle version 8.14.3 is +> incompatible with the Gradle JVM version 25 currently selected to run Gradle +> build. + +Fix: `Settings → Build, Execution, Deployment → Build Tools → Gradle → Gradle +JDK` → **17**. If none is listed, `Download JDK…` → version 17, vendor Eclipse +Temurin. + +Prefer 17 explicitly over Android Studio's "apply a compatible JDK" quick-fix, +which will likely pick 21. 17 is what `ci-tauri-android` pins, and matching it +means a local build and a CI build resolve identically. + +**Why 8.14.3 and not Gradle 9:** `cargo tauri android init` generated the wrapper +pin, and Gradle 9 removed `project.exec`, which the generated +`buildSrc/.../BuildTask.kt` still uses. The wrapper, the AGP pin and that file are +all tracked in this repo, so the bump is ours to make whenever it is worth doing — +it is scaffolding we inherited, not a requirement of Tauri. Tauri's own Android +layer targets `compileSdk 36` and registers back handling through +`OnBackPressedDispatcher`, so the library is current; only the template trails. + +## 2. The Gradle glue has to be generated once + +`settings.gradle` does `apply from: 'tauri.settings.gradle'`, and that file — with +`app/tauri.build.gradle.kts`, `app/tauri.properties`, +`app/src/main/assets/tauri.conf.json` and the compiled `.so` files — is generated +per build and gitignored. A fresh clone does not have them, and settings +evaluation happens before any Gradle task, so the sync fails before anything can +generate them. + +From `desktop/src-tauri`: + +```sh +cargo tauri android build --debug --target x86_64 +``` + +After that, Android Studio syncs cleanly. + +## Prerequisites + +Gradle shells out to `cargo tauri android android-studio-script` on every build, +so the Rust toolchain is required on the machine running Android Studio — the CI +image cannot stand in for it. + +```sh +rustup toolchain install 1.97.1 +rustup target add aarch64-linux-android x86_64-linux-android +cargo install tauri-cli --version 2.11.4 --locked +``` + +Via the SDK Manager, matching `CI-tauri-android/versions.env`: + +| | version | why it matters | +|---|---|---| +| Platform | API 36 | `compileSdk` / `targetSdk` | +| Build-Tools | 35.0.0 | AGP 8.11's default | +| **NDK** | 28.2.13676358 | the Rust core cannot cross-compile without it | +| Platform-Tools | latest | `adb` | + +```sh +export ANDROID_HOME=$HOME/Android/Sdk +export NDK_HOME=$ANDROID_HOME/ndk/28.2.13676358 +``` + +Node is needed too — `beforeBuildCommand` runs `npm ci && npm run build`, because +`generate_context!` compiles the frontend into the binary. + +## Emulator + +Create an AVD with an **x86_64** system image, API 24 or newer (`minSdk = 24`). +CI builds arm64-v8a and x86_64, so either runs, but x86_64 executes natively on a +desktop instead of being translated. + +## The dev loop + +Android Studio's Run button rebuilds the whole Rust core each time. For +iteration, with an emulator already running: + +```sh +cd desktop/src-tauri +cargo tauri android dev +``` + +That starts Vite, wires `adb reverse` so the emulator reaches +`localhost:5173`, and hot-reloads frontend changes without a rebuild. Android +Studio earns its keep for the debugger, logcat and layout inspection. + +## Known gaps, so they are not mistaken for bugs + +- **Safe areas / viewport** are not handled yet (task 2706) — content may sit + under a notch or the gesture bar. Deliberately left until a device could + verify it. +- **`android:enableOnBackInvokedCallback`** is absent from the manifest, so + predictive-back animations will not engage on Android 13+. Tauri registers the + dispatcher correctly; only the opt-in flag is missing. +- **`android:usesCleartextTraffic`** is templated in app-wide. A + `networkSecurityConfig` resource is the better shape — see Scribe note 2437, + which hit this on Minstrel. +- Debug builds are large and slow to start. Do not read either as the product.