From 68e77c7b37a3b0f10993fb706698184503c9b8f8 Mon Sep 17 00:00:00 2001 From: iris <2+iris@noreply.localhost> Date: Wed, 2 Sep 2026 05:33:50 -0400 Subject: [PATCH] Let build-apk.sh build either variant: ./build-apk.sh [release|debug] Dev Updater is gaining build modes declared per component as complete command lines, so the variant is a positional word and nothing else. Release stays the default and the only one that signs. Co-Authored-By: Claude Fable 5.1 --- AGENTS.md | 4 +++- app/build-apk.sh | 46 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 2dcc842..840e2d1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -204,7 +204,9 @@ first if a remote spawn ever mangles an argument. to produce the APK to install on a phone (through Dev Updater), or `./run-android.sh` to build, install, and launch on the emulator. **The phone gets the release build**, signed with a key the script - generates once under `~/.config/ai-app/release.jks` (never in the repo). + generates once under `~/.config/ai-app/release.jks` (never in the repo); + `./build-apk.sh debug` builds the other variant, and Dev Updater's build + modes call the script with exactly that word. The emulator scripts stay on the debug build; a debuggable build runs Compose at a fraction of release speed, so never read a frame time from one as the app's -- the render report now says which build it came from. diff --git a/app/build-apk.sh b/app/build-apk.sh index e617daa..2c49697 100755 --- a/app/build-apk.sh +++ b/app/build-apk.sh @@ -1,7 +1,13 @@ #!/bin/sh # Builds the app's APK, ready to install on a phone through Dev Updater. # -# ./build-apk.sh +# ./build-apk.sh the release build, signed (what the phone runs) +# ./build-apk.sh debug the debug build, for reproducing something the +# emulator scripts would build anyway +# +# Dev Updater's `.dev-updater.ron` at the checkout root spells these out as +# build modes, one command line each; it passes nothing else, so the word +# here is the whole interface. # # The APK pins the CA on *this* machine ($XDG_CONFIG_HOME/ai-app/certs/ca.pem, # or AI_APP_CA), so build it on the machine that runs the backend: an app @@ -15,6 +21,16 @@ # whatever is under this project's build directory. set -eu +VARIANT=${1:-release} +case "$VARIANT" in +release) TASK=assembleRelease ;; +debug) TASK=assembleDebug ;; +*) + echo "build-apk.sh: unknown variant '$VARIANT' (release, debug)" >&2 + exit 2 + ;; +esac + SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) cd "$SCRIPT_DIR" @@ -65,7 +81,7 @@ fi # uninstalling it first: the signatures differ, and Android refuses to # update across them. KEYSTORE="${AI_APP_KEYSTORE:-${XDG_CONFIG_HOME:-$HOME/.config}/ai-app/release.jks}" -if [ ! -f "$KEYSTORE" ]; then +if [ "$VARIANT" = release ] && [ ! -f "$KEYSTORE" ]; then KEYTOOL="${JAVA_HOME:+$JAVA_HOME/bin/keytool}" KEYTOOL="${KEYTOOL:-keytool}" if ! command -v "$KEYTOOL" >/dev/null 2>&1; then @@ -81,10 +97,12 @@ if [ ! -f "$KEYSTORE" ]; then -keyalg RSA -keysize 2048 -validity 10000 \ -storepass "$PASSWORD" -keypass "$PASSWORD" -dname "CN=ai-app" >/dev/null 2>&1) fi -AI_APP_KEYSTORE="$KEYSTORE" -AI_APP_KEYSTORE_PASSWORD=$(cat "$KEYSTORE.password") -export AI_APP_KEYSTORE AI_APP_KEYSTORE_PASSWORD -echo "==> Signing with $KEYSTORE" +if [ "$VARIANT" = release ]; then + AI_APP_KEYSTORE="$KEYSTORE" + AI_APP_KEYSTORE_PASSWORD=$(cat "$KEYSTORE.password") + export AI_APP_KEYSTORE AI_APP_KEYSTORE_PASSWORD + echo "==> Signing with $KEYSTORE" +fi # Dev Updater draws a real progress bar from "@@progress done/total" lines, # and ignores anything that isn't exactly that shape. Gradle can't be asked @@ -95,17 +113,17 @@ echo "==> Signing with $KEYSTORE" # the total. The build then prints one "> Task :x" line per task as it # goes, so counting those against it is the whole mechanism. # -# Task count is not time -- compileReleaseKotlin and dexBuilder are most of +# Task count is not time -- the Kotlin compile and dexBuilder are most of # the wall clock -- so the bar moves unevenly. It is still counted work # rather than a guess at how long last time took. -TASKS=$(./gradlew :androidApp:assembleRelease --dry-run --console=plain 2>/dev/null \ +TASKS=$(./gradlew :androidApp:$TASK --dry-run --console=plain 2>/dev/null \ | grep -c '^:[A-Za-z:]* SKIPPED' || true) echo "==> Building" if [ "${TASKS:-0}" -gt 0 ]; then echo "@@progress 0/$TASKS" DONE=0 - ./gradlew :androidApp:assembleRelease --console=plain 2>&1 | while IFS= read -r line; do + ./gradlew :androidApp:$TASK --console=plain 2>&1 | while IFS= read -r line; do echo "$line" case "$line" in "> Task "*) @@ -117,19 +135,19 @@ if [ "${TASKS:-0}" -gt 0 ]; then # The pipeline's exit status is the shell's, not gradle's, so ask # gradle again rather than reporting a failed build as a success. It is # up to date by now, so this is a second or two. - ./gradlew :androidApp:assembleRelease --console=plain >/dev/null + ./gradlew :androidApp:$TASK --console=plain >/dev/null else - ./gradlew :androidApp:assembleRelease + ./gradlew :androidApp:$TASK fi -APK="$SCRIPT_DIR/androidApp/build/outputs/apk/release/androidApp-release.apk" +APK="$SCRIPT_DIR/androidApp/build/outputs/apk/$VARIANT/androidApp-$VARIANT.apk" echo echo "==> Built $APK" [ -f "$APK" ] && ls -lh "$APK" | awk '{print " " $5}' echo echo "To get it onto the phone: add this project to Dev Updater (or hit" echo "Update on it if it's already there) and install from there." -echo "If the phone still has the old debug build, uninstall that first:" -echo "it is signed with a different key, so Android will refuse the update." +echo "Debug and release are signed with different keys, so switching from" +echo "one to the other means uninstalling the installed one first." echo "Then start the backend and scan the enrollment QR it prints:" echo " ./server/target/release/ai-server --rotate-token"