From 3627e9f9cfac1d321a97aeb79977eb994faed970 Mon Sep 17 00:00:00 2001 From: funman300 Date: Thu, 25 Jun 2026 11:16:38 -0700 Subject: [PATCH] fix(android): sign release APK v2+v3 only (drop invalid v1 JAR signature) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The apksigner step relied on auto scheme selection, which produced an APK carrying invalid v1 (JAR) signature files: META-INF/*.SF and *.RSA were present but failed v1 verification (apksigner reports `v1 scheme: false` while v2/v3 verify). Android installs such an APK fine via v2/v3, but Obtainium parses the legacy v1 certificate at install time, gets an empty cert list, and crashes with: RangeError (length): Invalid value: valid value range is empty: 0 This is why the app adds fine in Obtainium (Gitea API only) but fails on install (APK parse). minSdk is 26, so v1/JAR signing is unnecessary — sign explicit v2+v3 only (matching modern Android tooling for minSdk >= 24) and pass --min-sdk-version 26. Adds a post-sign guard that fails the build if any META-INF v1 signature files remain. Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/build_android_apk.sh | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/scripts/build_android_apk.sh b/scripts/build_android_apk.sh index 39c5119..1fc83ed 100755 --- a/scripts/build_android_apk.sh +++ b/scripts/build_android_apk.sh @@ -213,15 +213,35 @@ KEY_PASS="${KEY_PASS:-$KEYSTORE_PASS}" mkdir -p "$(dirname "$APK_OUT")" echo ">>> apksigner sign -> $APK_OUT" +# Sign the schemes explicitly instead of relying on apksigner's auto behaviour. +# Left to "auto", this pipeline produced an APK carrying invalid v1 (JAR) +# signature files (META-INF/*.SF/.RSA present but failing v1 verification). +# Android installs it fine via v2/v3, but Obtainium parses the APK's legacy v1 +# certificate at install time, gets an empty cert list, and crashes with +# "RangeError (length): Invalid value: valid value range is empty: 0". +# minSdk is 26 (solitaire_app/android/AndroidManifest.xml), so v1/JAR signing is +# not needed at all — disable it and ship a clean v2+v3 signature, matching what +# modern Android tooling produces for minSdk >= 24. "$BT/apksigner" sign \ --ks "$KEYSTORE" \ --ks-pass "pass:$KEYSTORE_PASS" \ --ks-key-alias "$KEY_ALIAS" \ --key-pass "pass:$KEY_PASS" \ + --min-sdk-version 26 \ + --v1-signing-enabled false \ + --v2-signing-enabled true \ + --v3-signing-enabled true \ --out "$APK_OUT" \ "$STAGING/app-aligned.apk" echo ">>> verify" -"$BT/apksigner" verify --verbose "$APK_OUT" +"$BT/apksigner" verify --min-sdk-version 26 --verbose "$APK_OUT" + +# Guard: no leftover v1/JAR signature files may remain — their presence (valid or +# not) is what tripped Obtainium. Fail the build if any slipped through. +if unzip -l "$APK_OUT" 2>/dev/null | grep -qiE 'META-INF/.*\.(SF|RSA|DSA|EC)$'; then + echo "ERROR: APK still contains v1/JAR signature files; expected v2+v3 only" >&2 + exit 1 +fi echo ">>> done: $APK_OUT"