docs: how to run the Android client locally (task 1864)
Two things stop a fresh clone from opening in Android Studio, and both fail with errors that name the wrong culprit — so they are written down rather than rediscovered. Android Studio runs Gradle on its bundled JDK 25, which Gradle 8.14.3 rejects with an "Incompatible Gradle JVM version" message that reads like a project misconfiguration. And settings.gradle applies tauri.settings.gradle, which is generated per build and gitignored, so sync fails before anything can create it — one CLI build fixes that permanently. Also records why the Gradle pin is what it is, since the question came up and the answer was not what it first looked like: the wrapper, the AGP pin and the buildSrc file using the removed project.exec are all TRACKED in this repo. It is scaffolding tauri android init wrote once, ours to bump when it is worth doing, not a constraint of the framework. Tauri's own Android layer targets compileSdk 36 and registers back handling through OnBackPressedDispatcher — the library is current, only the generated template trails. Known gaps are listed so a tester does not file them as bugs: no safe-area handling yet (2706), no enableOnBackInvokedCallback so predictive back will not animate, and the templated app-wide usesCleartextTraffic that Minstrel already hit as a Play Protect smell. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user