Files
mtgc/scripts/android-setup.sh

272 lines
10 KiB
Bash
Raw Normal View History

Add Android support via Tauri 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.
2026-08-02 13:16:34 -05:00
#!/usr/bin/env bash
#
# android-setup.sh — one-time Android build environment setup for mtgc.
#
# Installs the pieces `cargo tauri android` needs that Android Studio does NOT
# install by default: the SDK command-line tools, the NDK (required to
# cross-compile the Rust core — see "Why the NDK is mandatory" below), and the
# Rust Android targets.
#
# Assumes the Android SDK itself already exists (Android Studio's first-run
# wizard creates it at ~/Android/Sdk). Set ANDROID_HOME to override.
#
# Safe to re-run: every step is skipped if already satisfied.
#
# Usage:
# ./scripts/android-setup.sh
# ANDROID_HOME=/opt/android-sdk ./scripts/android-setup.sh
# NDK_VERSION=27.2.12479018 ./scripts/android-setup.sh # pin instead of latest
#
# Why the NDK is mandatory (not just nice to have): mtgc-core builds rusqlite
# with the `bundled` feature, which compiles the SQLite C amalgamation, and
# rustls pulls in `ring` (C/asm). Both need a C cross-toolchain. The bundled
# SQLite can't be swapped for Android's system libsqlite3 either — the card
# schema uses FTS5 with the `trigram` tokenizer, which platform SQLite on many
# Android versions lacks entirely.
#
set -euo pipefail
info() { printf '\033[1;34m==>\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m[warn]\033[0m %s\n' "$*"; }
err() { printf '\033[1;31m[err]\033[0m %s\n' "$*" >&2; }
ANDROID_HOME="${ANDROID_HOME:-$HOME/Android/Sdk}"
# Bump if Google publishes a newer bundle; the URL pattern is stable.
CMDLINE_TOOLS_BUILD="${CMDLINE_TOOLS_BUILD:-13114758}"
CMDLINE_TOOLS_URL="https://dl.google.com/android/repository/commandlinetools-linux-${CMDLINE_TOOLS_BUILD}_latest.zip"
# Pinned to a known-good *stable* NDK on purpose. sdkmanager also publishes beta
# and canary channels whose version numbers sort higher (e.g. 30.0.15729638 is
# r30-beta2), so "install the newest" silently lands you on a prerelease
# toolchain — not what you want compiling SQLite and ring. Override with
# NDK_VERSION=... if you need a different one.
DEFAULT_NDK_VERSION="28.2.13676358"
RUST_TARGETS=(
aarch64-linux-android # 64-bit ARM — virtually all real devices
armv7-linux-androideabi # 32-bit ARM — older devices
i686-linux-android # 32-bit x86 emulator
x86_64-linux-android # 64-bit x86 emulator (the fast one on a desktop)
)
# --- 1. Prerequisites ------------------------------------------------------
if ! command -v rustc >/dev/null 2>&1; then
err "Rust not found. Install from https://rustup.rs and re-run."
exit 1
fi
info "Rust: $(rustc --version)"
if cargo tauri --version >/dev/null 2>&1; then
info "Tauri CLI: $(cargo tauri --version 2>&1 | head -1)"
else
err "Tauri CLI not found. Run ./scripts/devel-setup.sh first."
exit 1
fi
# --- 2. A JDK the Android Gradle Plugin actually accepts -------------------
#
# Gradle 9.6 / AGP 9 run on JDK 17 through 25 (25 is the newest tested; an
# older Gradle choked on 25, so an untested newer JDK is skipped, not trusted).
Add Android support via Tauri 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.
2026-08-02 13:16:34 -05:00
#
# Android Studio's bundled JetBrains Runtime is preferred, then the newest
# system JDK in range. Every candidate's major version is checked (from its
# `release` file) rather than assumed. Note we test for bin/javac specifically —
# a JRE-only or leftover-empty /usr/lib/jvm directory must not count.
# Succeeds if $1 is a JDK of a version Gradle accepts (17 through 25).
jdk_ok() {
[ -x "$1/bin/javac" ] || return 1
local v
v="$(sed -n 's/^JAVA_VERSION="\([0-9]*\).*/\1/p' "$1/release" 2>/dev/null)"
[ -n "$v" ] && [ "$v" -ge 17 ] && [ "$v" -le 25 ]
}
Add Android support via Tauri 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.
2026-08-02 13:16:34 -05:00
find_jdk() {
# Explicit override wins.
if [ -n "${ANDROID_JAVA_HOME:-}" ] && [ -x "${ANDROID_JAVA_HOME}/bin/javac" ]; then
echo "$ANDROID_JAVA_HOME"; return 0
fi
# Android Studio's bundled JBR (Toolbox or standalone install locations),
# then the newest system JDK (Fedora or Adoptium packages) in range.
Add Android support via Tauri 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.
2026-08-02 13:16:34 -05:00
for d in \
"$HOME/.local/share/JetBrains/Toolbox/apps/android-studio/jbr" \
"$HOME/.local/share/JetBrains/Toolbox/apps/android-studio"/*/jbr \
"$HOME/android-studio/jbr" \
/opt/android-studio/jbr \
$(ls -d /usr/lib/jvm/* 2>/dev/null | sort -rV)
Add Android support via Tauri 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.
2026-08-02 13:16:34 -05:00
do
jdk_ok "$d" && { echo "$d"; return 0; }
Add Android support via Tauri 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.
2026-08-02 13:16:34 -05:00
done
return 1
}
if JDK_PATH="$(find_jdk)"; then
export JAVA_HOME="$JDK_PATH"
info "Android JDK: $JAVA_HOME ($("$JAVA_HOME/bin/java" -version 2>&1 | head -1))"
else
err "No JDK 17 through 25 found."
err "Fix: sudo dnf install java-25-openjdk-devel"
Add Android support via Tauri 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.
2026-08-02 13:16:34 -05:00
err "or: ANDROID_JAVA_HOME=/path/to/jdk ./scripts/android-setup.sh"
exit 1
fi
# --- 3. Android SDK --------------------------------------------------------
if [ ! -d "$ANDROID_HOME" ]; then
err "No Android SDK at $ANDROID_HOME"
err "Install Android Studio and run it once (its setup wizard downloads the SDK),"
err "or set ANDROID_HOME to an existing SDK."
exit 1
fi
info "Android SDK: $ANDROID_HOME"
# --- 4. SDK command-line tools (provides sdkmanager) -----------------------
SDKMANAGER="$(find "$ANDROID_HOME/cmdline-tools" -name sdkmanager -type f 2>/dev/null | head -1 || true)"
if [ -z "$SDKMANAGER" ]; then
info "cmdline-tools not present — installing (build $CMDLINE_TOOLS_BUILD)…"
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
curl -fL --progress-bar -o "$tmp/cmdline-tools.zip" "$CMDLINE_TOOLS_URL"
unzip -q "$tmp/cmdline-tools.zip" -d "$tmp"
# sdkmanager expects to live at cmdline-tools/latest/, not cmdline-tools/.
mkdir -p "$ANDROID_HOME/cmdline-tools"
rm -rf "$ANDROID_HOME/cmdline-tools/latest"
mv "$tmp/cmdline-tools" "$ANDROID_HOME/cmdline-tools/latest"
SDKMANAGER="$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager"
fi
info "sdkmanager: $SDKMANAGER"
sdk() { "$SDKMANAGER" --sdk_root="$ANDROID_HOME" "$@"; }
# Accept licenses up front so the installs below don't block on a prompt.
info "Accepting SDK licenses…"
yes 2>/dev/null | sdk --licenses >/dev/null || true
# --- 5. NDK ----------------------------------------------------------------
NDK_VERSION="${NDK_VERSION:-$DEFAULT_NDK_VERSION}"
NDK_DIR="$ANDROID_HOME/ndk/$NDK_VERSION"
if [ -d "$NDK_DIR" ]; then
info "NDK already installed: $NDK_DIR"
else
info "Installing NDK $NDK_VERSION (large download)…"
sdk --install "ndk;$NDK_VERSION"
fi
[ -d "$NDK_DIR" ] || { err "NDK install did not produce $NDK_DIR"; exit 1; }
# Surface the actual release name so a prerelease can't slip by unnoticed.
NDK_RELEASE="$(sed -n 's/^Pkg.Revision *= *//p' "$NDK_DIR/source.properties" 2>/dev/null)"
info "NDK: $NDK_DIR (revision ${NDK_RELEASE:-unknown})"
case "$NDK_RELEASE" in
*beta*|*rc*|*canary*) warn "This NDK is a prerelease — pin a stable NDK_VERSION if builds misbehave." ;;
esac
# --- 6. Rust Android targets ----------------------------------------------
installed="$(rustup target list --installed)"
for t in "${RUST_TARGETS[@]}"; do
if grep -qx "$t" <<<"$installed"; then
info "rust target present: $t"
else
info "adding rust target: $t"
rustup target add "$t"
fi
done
# --- 7. Make Android Studio findable by its canonical XDG name -------------
#
# `cargo tauri android dev --open` (cargo-mobile2) locates Studio by scanning
# XDG data dirs for a .desktop entry whose Name is *exactly* "Android Studio",
# then running its Exec line. A standalone install writes that name, but
# 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 — which fails with a confusing ENOENT. Drop in a hidden
# shim entry when no exact match exists.
xdg_app_dirs() {
echo "${XDG_DATA_HOME:-$HOME/.local/share}/applications"
local IFS=:
for d in ${XDG_DATA_DIRS:-/usr/local/share:/usr/share}; do echo "$d/applications"; done
}
has_studio_entry() {
local d f
while read -r d; do
[ -d "$d" ] || continue
for f in "$d"/*.desktop; do
[ -f "$f" ] || continue
# Name= must match exactly, and only within the [Desktop Entry] section.
if grep -qx 'Name=Android Studio' "$f"; then return 0; fi
done
done < <(xdg_app_dirs)
return 1
}
find_studio_exec() {
# Prefer an Exec line already written by Toolbox (it tracks the real path);
# otherwise fall back to well-known install locations.
local f exec_line d
for f in "${XDG_DATA_HOME:-$HOME/.local/share}"/applications/jetbrains-studio-*.desktop; do
[ -f "$f" ] || continue
exec_line="$(sed -n 's/^Exec=//p' "$f" | head -1)"
[ -n "$exec_line" ] && { echo "$exec_line"; return 0; }
done
for d in \
"$HOME/.local/share/JetBrains/Toolbox/apps/android-studio/bin/studio" \
"$HOME/android-studio/bin/studio.sh" \
/opt/android-studio/bin/studio.sh
do
[ -x "$d" ] && { echo "\"$d\" %u"; return 0; }
done
return 1
}
if has_studio_entry; then
info "Android Studio is discoverable by name (--open will work)"
elif STUDIO_EXEC="$(find_studio_exec)"; then
APPS="${XDG_DATA_HOME:-$HOME/.local/share}/applications"
mkdir -p "$APPS"
cat > "$APPS/android-studio.desktop" <<DESKTOP
[Desktop Entry]
# Shim so tools that look up Android Studio by its canonical XDG name can find
# a JetBrains Toolbox install, which names its entry with the release version.
# Written by mtgc's scripts/android-setup.sh. Safe to delete.
Type=Application
Name=Android Studio
Exec=$STUDIO_EXEC
Categories=Development;IDE;
Terminal=false
StartupWMClass=jetbrains-studio
NoDisplay=true
DESKTOP
info "wrote $APPS/android-studio.desktop so 'tauri android dev --open' can find Studio"
else
warn "Android Studio not found — 'cargo tauri android dev --open' won't be able to launch it."
warn "Run 'cargo tauri android dev' and open src-tauri/gen/android in Studio yourself."
fi
# --- 8. The environment the build needs ------------------------------------
Add Android support via Tauri 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.
2026-08-02 13:16:34 -05:00
cat <<EOF
$(info "Setup complete.")
Add these to your shell profile (or export them before building):
export ANDROID_HOME="$ANDROID_HOME"
export NDK_HOME="$NDK_DIR"
export JAVA_HOME="$JAVA_HOME" # a JDK 17–25 that Gradle accepts
Add Android support via Tauri 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.
2026-08-02 13:16:34 -05:00
Then, from the project root:
cargo tauri android init # once — scaffolds src-tauri/gen/android
cargo tauri android dev # run on an emulator or adb-connected device
cargo tauri android build # build APK/AAB
Devices/emulators: $ANDROID_HOME/platform-tools/adb devices
EOF