- The Android SDK in `/opt/android-sdk` (`ANDROID_HOME`): command-line tools 23.0 (checked against Google's published SHA-1), `platforms;android-37.0`, `build-tools;36.0.0` and `ndk;30.0.16248370`, licences accepted.
7
- Gradle 9.6.0 as `gradle` (checked against its published SHA-256). Jobs run `gradle --offline`, not `./gradlew`, which would download its distribution.
8
- Rust 1.97.1 with the `aarch64-linux-android` and `x86_64-linux-android` targets and cargo-ndk 4.1.2, for the app's `rust-core`.
9
-`rust-core`'s crates, vendored in `/opt/vendor`; `/.cargo/config.toml` points cargo at them, as in the rust image.
10
- The app's Gradle dependencies in `/opt/gradle-home/caches`, fetched by building the app once while the image is built.
11
12
The Gradle cache is read-only in the guest. A job points `GRADLE_RO_DEP_CACHE` at it and gives Gradle its own writable `GRADLE_USER_HOME`, so Gradle reads dependencies from the image and writes everything else under `/tmp`.
`build.sh` expects the app next to this repository (`../oxygenhub-android`, subrepos checked out). It downloads and checks the command-line tools and Gradle into `images/android/dl/`, copies the app without its build output, vendors `rust-core`'s crates, then builds the image with Docker and exports it as a plain tarball. The tarball is about 6 GB, so build it where the disk has room (Earth) and delete it once imported.
23
24
Rebuild and re-import when the app changes its SDK, NDK, Gradle or dependency versions, or `rust-core/Cargo.lock` changes, then pin the new hash in the app's pipeline. A dependency missing from the image fails the job with Gradle's "No cached version … available for offline mode", or cargo's "no matching package".
25
26
##Using it
27
28
```kdl
29
sandbox "android" {
30
runtime "microvm"
31
rootfs "cas://blob/<hash printed by flow rootfs import>"