#!/usr/bin/env bash # The detour build (ANDROID.md): cargo → strip → copy → gradle. Run from anywhere. set -euo pipefail cd /f/Coding/SoulStream source src-tauri/android/env.sh # Which build. The default is exactly what this script has always done, and # has to stay that way: deploy.sh calls it with no argument every twenty # minutes, and ship.sh calls deploy.sh. `--release` (or SS_ANDROID_RELEASE=1) # is the other path, and as of this round nobody has run it — see ANDROID.md # → "The release build (nobody has made one yet)". REL=0 case "${1:-}" in --release) REL=1 ;; "") ;; *) echo "usage: build.sh [--release]"; exit 2 ;; esac if [ "${SS_ANDROID_RELEASE:-0}" = "1" ]; then REL=1; fi if [ "$REL" = "1" ]; then PROFILE=release VARIANT=Arm64Release # --features is repeatable and cargo unions them, so custom-protocol on # the cargo line below is kept. devtools is not a nicety: wry compiles the # setWebContentsDebuggingEnabled call only under # cfg(any(debug_assertions, feature = "devtools")), so a plain release APK # opens no webview_devtools_remote socket and `smoke.mjs --phone` cannot # attach to the one build that most needs walking. R8 never sees it. CARGO_EXTRA="--release --features tauri/devtools" test -d src-tauri/gen/android/app || { echo "no generated Android project — run the CLI's android init first"; exit 1; } # The app-wide keep rules, into a project that cannot hold them itself: # gen/ is regenerated and gitignored. The release build type globs # **/*.pro out of this directory; the debug type reads none of them. cp src-tauri/android/proguard-soulstream.pro src-tauri/gen/android/app/proguard-soulstream.pro echo "== RELEASE: R8 on, rules from src-tauri/android/proguard-soulstream.pro + each plugin's consumer-rules.pro" else PROFILE=debug VARIANT=Arm64Debug CARGO_EXTRA="" fi echo "== cargo $(date +%T)" cargo build --lib -p app --target aarch64-linux-android --features tauri/custom-protocol $CARGO_EXTRA 2>&1 | grep -v "^\s*Compiling\|^\s*Fresh" # the grep above hides cargo's exit code; a failed compile must not package # the previous library as if it were this one test "${PIPESTATUS[0]}" -eq 0 || { echo "cargo failed — not packaging"; exit 1; } SO=target/aarch64-linux-android/$PROFILE/libapp_lib.so test -f "$SO" || { echo "no .so built"; exit 1; } echo "== strip $(date +%T)" DEST=src-tauri/gen/android/app/src/main/jniLibs/arm64-v8a mkdir -p "$DEST" cp "$SO" "$DEST/libapp_lib.so" "$BIN/llvm-strip.exe" --strip-debug "$DEST/libapp_lib.so" ls -la "$DEST/libapp_lib.so" echo "== gradle $(date +%T)" cd src-tauri/gen/android ./gradlew.bat assemble$VARIANT -x rustBuild$VARIANT -q 2>&1 | grep -v "^$" | tail -20 || true cd /f/Coding/SoulStream if [ "$REL" = "1" ]; then UNSIGNED=src-tauri/gen/android/app/build/outputs/apk/arm64/release/app-arm64-release-unsigned.apk if [ ! -f "$UNSIGNED" ]; then echo "no release APK — gradle's tail is above. The two failures we expect:" echo " R8 missing class — its own list is at src-tauri/gen/android/app/build/outputs/mapping/arm64Release/missing_rules.txt;" echo " add what it names to src-tauri/android/proguard-soulstream.pro and run again" echo " lintVital — re-run gradle by hand with -x lintVitalArm64Release" echo " (AGP 8 splits it; -x lintVitalAnalyzeArm64Release may be the one)" exit 1 fi KS="$HOME/.android/debug.keystore" test -f "$KS" || { echo "no $KS — the release APK is unsigned and no phone will install it"; exit 1; } BT="$(ls -d "$SDK"/build-tools/* 2>/dev/null | sort -V | tail -1 || true)" test -n "$BT" || { echo "no build-tools under $SDK — cannot sign"; exit 1; } APK=src-tauri/gen/android/app/build/outputs/apk/arm64/release/app-arm64-release.apk echo "== sign $(date +%T) ($(basename "$BT"))" "$BT/zipalign.exe" -p -f 4 "$UNSIGNED" "$APK" # The SAME key the debug builds are signed with, deliberately. A release # APK signed with any other key cannot be installed over the app already # on the phone, and the obvious next move — uninstall, then install — # takes the app's data with it. This is a test build, not a distributable # one; a real one needs a real key and this script is not where that goes. MSYS_NO_PATHCONV=1 "$BT/apksigner.bat" sign --ks "$(cygpath -w "$KS")" --ks-key-alias androiddebugkey --ks-pass pass:android --key-pass pass:android "$APK" else APK=src-tauri/gen/android/app/build/outputs/apk/arm64/debug/app-arm64-debug.apk fi ls -la "$APK" echo "== done $(date +%T)"