The phone has been wearing tauri's logo. `tauri android init` writes the
generated project's `res/` from its own template and never reads
`src-tauri/icons/android/`, which has carried the falcon since 50afa6a, and the
detour build runs cargo and Gradle directly — so nothing ever copied it across:
the two dominant colours in the packaged `mipmap-xxxhdpi/ic_launcher.png` are
`#24c8db` and `#ffc131`, tauri's own brand cyan and amber. `src-tauri/android/res/`
is the app module's res now, tracked, and `build.sh` and `dev.sh` copy the whole
tree into `gen/android` before Gradle, because that project is regenerated and
gitignored and an asset that only lives there is an asset that disappears.
It is a real adaptive icon: the kit's foreground and its **monochrome** layer at
five densities, the legacy mipmaps under it, and the background as one
`#FF05080B` colour resource rather than five identical flat PNGs, so the gradient
being mocked separately replaces one file. The kit's own XML could not ship — it
points every layer at `@drawable/` while shipping them as PNGs under `mipmap-*`,
and in the generated project two of those three references resolve to Android
Studio's template robot rather than failing — so the overlay's XML says
`@mipmap/` and `@color/`, and its colour file takes the same name tauri's does,
because two files declaring one colour is a hard aapt2 error.
Losing the copy would be silent — the APK still builds, still installs, and wears
the old logo with nothing in the log — so `verify-icon.sh` opens every APK both
scripts make and reads the resources back out: the two `mipmap-anydpi-v26` XMLs
present, and four PNG names at five densities byte for byte from the overlay. A
release APK keeps neither the bytes nor the names — AGP re-encodes every PNG and
shortens every resource path — so that path asks `aapt2 dump resources` what each
name points at and compares pixel dimensions instead; 72×72 at hdpi still tells
the kit's icon from tauri's 49×49. No walk step: a launcher icon is not reachable
from inside the app, and the masking and the themed layer want a minute with the
phone's home screen.
96 lines
5.3 KiB
Bash
96 lines
5.3 KiB
Bash
#!/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"
|
|
# The launcher identity, into a project that cannot keep it: gen/android is
|
|
# regenerated by the tauri CLI and gitignored, and the detour build never runs
|
|
# that CLI, so the res it holds is still the one `android init` wrote — tauri's
|
|
# own logo. Everything under src-tauri/android/res/ is copied over it on every
|
|
# build. The whole tree, not a file list: a later round adding a resource adds
|
|
# a file there and this line does not change.
|
|
echo "== res overlay $(date +%T)"
|
|
test -d src-tauri/android/res || { echo "src-tauri/android/res is gone — the APK would wear tauri's logo and say nothing"; exit 1; }
|
|
cp -r src-tauri/android/res/. src-tauri/gen/android/app/src/main/res/
|
|
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"
|
|
bash src-tauri/android/verify-icon.sh "$APK" $([ "$REL" = "1" ] && echo --crunched)
|
|
echo "== done $(date +%T)"
|