Android Studio now bundles JBR 25, which Gradle 8.14's embedded Kotlin
can't parse. Follow Tauri's current template: Gradle 9.6.1, Kotlin 2.2.10,
the builtInKotlin/newDsl/failOnMissingFiles compatibility flags, the
compilerOptions DSL, and ExecOperations in BuildTask (project.exec is gone
in Gradle 9). AGP goes to 9.4.1 rather than the template's 9.3.1.
Release lint vital is turned off: AGP 9.3/9.4's lint crashes analysing the
.gradle.kts scripts (findFirCompiledSymbol), failing every release build.
The env scripts now accept JDK 17 through 25, preferring Studio's JBR.
Check each JDK candidate's major version instead of assuming Android Studio's
JBR is 21, look for Adoptium temurin-{21,17}-jdk (Fedora 44 dropped
java-21-openjdk), and propagate android-env.sh failures to scripts that
source it so fdroid-publish.sh stops before building.
cargo-mobile2 locates Studio by scanning XDG data dirs for a .desktop entry
whose Name is exactly "Android Studio", then runs its Exec line. A standalone
install writes that name; JetBrains Toolbox writes a versioned one ("Android
Studio Quail 2 2026.1.2 Patch 1"), so the lookup misses and it falls back to
running "Android Studio" as a literal command, failing with an ENOENT that
names every env var except the actual problem.
android-setup.sh now writes a hidden shim entry when no exact-name match
exists, reusing the Exec line Toolbox already generated rather than hardcoding
a path. Idempotent: a later run reports Studio as discoverable and rewrites
nothing.
The Rust core was already portable (caller-provided db paths, rustls rather
than openssl) and the shell already had the mobile entry point, so this is
mostly toolchain, provisioning, and platform-gating.
Toolchain:
- scripts/android-setup.sh installs what Android Studio doesn't: SDK
cmdline-tools, a pinned stable NDK, and the Rust Android targets. The NDK is
pinned rather than "latest" because sdkmanager's newest is often a beta
(30.0.15729638 is r30-beta2) -- not something to compile SQLite with. Prefers
Android Studio's bundled JDK 21, since Gradle rejects newer JDKs.
- Track src-tauri/gen/android (excluding build output): AndroidManifest.xml is
hand-edited and Android permissions have no tauri.conf.json equivalent.
- vite: serve on TAURI_DEV_HOST so a device/emulator can reach the dev server.
Card data: downloading streams ~740MB to build a ~73MB db, which is rough on a
phone. Add import_reference_db to adopt a desktop-built file instead, validated
by db::inspect_reference_db first so picking the wrong file is a clean error
rather than a broken install. Installs via copy-then-rename so an interrupted
copy can't leave a partial db.
Ingest hardening (helps desktop too):
- Give ureq connect/read timeouts. Cancellation is only polled per parsed
record, so a stalled socket previously hung forever with no way to cancel.
- Drop the remove_file before rename; POSIX rename already replaces atomically,
and the delete-first window could leave no reference.db at all if the process
was killed -- much likelier on Android.
UI: hide Open/New Library on mobile (scoped storage has no arbitrary-path
equivalent, and SQLite can't open a content:// URI), reported via a cfg!(mobile)
flag on Status rather than user-agent sniffing. Use 100dvh so the soft keyboard
doesn't break the shell.
Verified: 70/70 core tests, desktop build clean, and the aarch64 APK builds
(bundled SQLite C and ring both cross-compile under NDK 28). Not yet run on a
device.