# aapt2 is beside the zipalign and apksigner build.sh has just used. Found # here rather than in the release branch below, because both build types want # it now: only the resource table can say what resolves to. SDKU="" [ -n "${ANDROID_HOME:-}" ] && SDKU="$(cygpath -u "$ANDROID_HOME" 2>/dev/null || echo "")" [ -z "$SDKU" ] && [ -n "${LOCALAPPDATA:-}" ] && SDKU="$(cygpath -u "$LOCALAPPDATA" 2>/dev/null || echo "")/Android/Sdk" A2="$(ls -1 "$SDKU"/build-tools/*/aapt2.exe 2>/dev/null | sort -V | tail -1 || true)" # 2. the ground, in BOTH build types. Not "is the file in the APK" — the # adaptive icon's is a REFERENCE, so what matters is what it # resolves to, and that is the one question a stale APK answers wrongly # while every other check still passes. (build.sh pipes Gradle through # `| tail -20 || true` and then runs `ls -la "$APK"`, so a Gradle run that # failed leaves the PREVIOUS build's APK exactly where the next step looks # for it.) Everything below comes out of the resource table and never out # of a path: a release APK has had res/mipmap-anydpi-v26/ic_launcher.xml # renamed to res/BW.xml, and the table is the only thing that still knows. TBL="" [ -n "$A2" ] && { TBL="$("$A2" dump resources "$APK" 2>/dev/null)" || bad "aapt2 could not read the resource table of $APK"; } # name [config] -> the file that resource points at. The config is not # optional detail: mipmap/ic_launcher has SIX entries — the anydpi adaptive # XML and five legacy PNGs — so a name-only lookup hands back # res/mipmap-mdpi-v4/ic_launcher.png and the whole check collapses. An empty # config means the entry with no qualifier at all, which is what a plain # drawable has. "anydpi" matches the "anydpi-v26" too, as look() does. path_of() { echo "$TBL" | awk -v n="$1" -v c="${2:-}" ' $1 == "resource" && $3 == n { f = 1; next } /^[ \t]*resource 0x/ { f = 0 } f { cfg = $1; gsub(/[()]/, "", cfg) if (c == "" || cfg == c || cfg ~ "^" c "-v[0-9]+$") for (i = 1; i <= NF; i++) if ($i ~ /^res\//) { print $i; exit } }'; } name_of() { echo "$TBL" | awk -v id="$1" '$1 == "resource" && $2 == id { print $3; exit }'; } if [ -z "$TBL" ]; then echo "== ground: NOT CHECKED — no aapt2 under ${SDKU:-(no SDK path)}/build-tools." echo " What points at is a resource id; only the table reads it." elif echo "$TBL" | grep -q "0_resource_name_obfuscated"; then echo "== ground: NOT CHECKED — this APK's resource names are collapsed." else ADAPT="$(path_of mipmap/ic_launcher anydpi)" test -n "$ADAPT" || bad "mipmap/ic_launcher has no anydpi entry in this APK — the adaptive icon is not in it, so $RES never reached src-tauri/gen/android/app/src/main/res" BGID="$("$A2" dump xmltree "$APK" --file "$ADAPT" 2>/dev/null \ | awk '/E: background/ { f = 1 } f && /android:drawable\(/ { sub(/.*=@?/, ""); print; exit }')" test -n "$BGID" || bad "the adaptive icon in this APK ($ADAPT) declares no " BGNAME="$(name_of "$BGID")" [ "$BGNAME" = "drawable/ic_launcher_ground" ] \ || bad "the APK's adaptive background is ${BGNAME:-$BGID}, not drawable/ic_launcher_ground — a stale APK, or the overlay did not reach src-tauri/gen/android/app/src/main/res" # and that what it resolves to is still concept 04 rather than a flat # fill. aapt:attr lifts each inline out into a resource of its # own, so the two fills are references as well; follow the ids rather than # the $name__N filenames aapt2 happens to give them this version. GPATH="$(path_of drawable/ic_launcher_ground)" test -n "$GPATH" || bad "drawable/ic_launcher_ground resolves to no file in this APK" GTREE="$("$A2" dump xmltree "$APK" --file "$GPATH" 2>/dev/null)" || bad "aapt2 cannot read $GPATH out of this APK" IDS="$(echo "$GTREE" | grep -oE 'fillColor\(0x[0-9a-f]+\)=@0x[0-9a-f]+' | grep -oE '0x[0-9a-f]+$')" NFILL="$(echo "$IDS" | grep -c . || true)" [ "$NFILL" = 2 ] || bad "the ground in this APK has $NFILL gradient fills, not 2 — concept 04 is a surface and the glow over it" STOPS="" for id in $IDS; do g="$(path_of "$(name_of "$id")")" test -n "$g" || bad "the ground's gradient $id has no file in the resource table" STOPS="$STOPS $("$A2" dump xmltree "$APK" --file "$g" | grep -oE 'color\(0x[0-9a-f]+\)=#[0-9a-f]{8}' | grep -oE '[0-9a-f]{8}$' | tr '\n' ' ')" done for c in ff0a2330 ff07141f ff040a10 2e31c0cb 0d1f8fc9 0007141f; do echo "$STOPS" | grep -qw "$c" || bad "the ground in this APK has lost concept 04's stop #$c" done echo "== ground: = $BGNAME, concept 04's six stops, read back out of the APK" fi # What none of this can see is a pixel. Whether the gradient BANDS on the # phone's OLED, how the glow reads under the Pixel's mask and how the falcon # sits on a lit ground rather than a flat one are a launcher screenshot, not a # resource table.