Skip to content

fix(android): don't block APK update when signing info is unavailable#71

Merged
huhuanming merged 3 commits into
mainfrom
fix/android-apk-verify-signature-unavailable
Jun 25, 2026
Merged

fix(android): don't block APK update when signing info is unavailable#71
huhuanming merged 3 commits into
mainfrom
fix/android-apk-verify-signature-unavailable

Conversation

@huhuanming

@huhuanming huhuanming commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Problem

PM report: upgrading the Android app 6.1.0 → 6.3.0 fails at the last verification step with 「安装包完整性检查失败 - 安装不安全」 (APK integrity check failed — unsafe to install).

Device: HUAWEI SEA-AL10, Android 10 (API 29), EMUI, APK ~194 MB.

Root cause (proven from logs)

The update pipeline is download → downloadASC → verifyASC → verifyPackage. The first three steps passed:

verifyASC: GPG signature + SHA256 verification passed

verifyASC GPG-verifies the detached .asc and secureCompares the downloaded file's SHA-256 against the signed hash. Passing it proves the 194 MB file on disk is byte-for-byte the authentic OneKey APK — corruption / bad download is ruled out.

It then died in verifyAPK:

verifyAPK: signing info unavailable (apkSigners=false, installedSigners=true)
→ java.lang.Exception: SIGNATURE_UNAVAILABLE

PackageManager.getPackageArchiveInfo(apkPath, GET_SIGNING_CERTIFICATES) returned null signers for the archive, while the installed app's signers read back fine. On some OEM ROMs (Huawei/EMUI on Android 9–10) and for large APKs, the platform cannot re-parse the archive's signing block and returns null even for a valid, untampered APK. The old code treated this asymmetric "can't read the archive's signers" identically to "signature is forged" and hard-threw SIGNATURE_UNAVAILABLE, blocking a legitimate update.

Why it's safe to skip

This signing-cert cross-check is defense-in-depth only:

  1. verifyASC already proved authenticity via GPG + SHA-256 before verifyAPK runs.
  2. Android's PackageInstaller re-verifies the signing certificate at install time — an update signed with a different cert is rejected with INSTALL_FAILED_UPDATE_INCOMPATIBLE.

So failing the whole update because a redundant check couldn't read the signers is strictly worse than letting the OS make the final call.

Change

Minimal: in both verifyAPK branches (API ≥ P GET_SIGNING_CERTIFICATES, and legacy GET_SIGNATURES), when the signers are null/unavailable, just log it at info level and skip the check instead of throwing SIGNATURE_UNAVAILABLE.

  • A genuine certificate MISMATCH (both sides readable, certs differ) → still hard-fails with SIGNATURE_MISMATCH.
  • Normal devices are unchanged.

Testing notes

  • Standalone build not run here (Nitro module needs the consuming app's Android classpath). Diff is minimal; logic reviewed manually.
  • Suggested follow-up to disambiguate scope (device-quirk vs a 6.3.0 signing/zip-structure regression): aggregate softwareUpdateResult events with failedStep=verifyPackage + SIGNATURE_UNAVAILABLE and check whether it's Huawei-only or all Android ≤10; and compare apksigner verify -v --print-certs v1/v2/v3 scheme flags between the 6.1.0 and 6.3.0 release APKs.

https://claude.ai/code/session_01NwuZPQd7xBE8S7KFtdkT9Y

verifyAPK hard-failed with SIGNATURE_UNAVAILABLE whenever
PackageManager.getPackageArchiveInfo(...) returned null signers for the
downloaded APK. On some OEM ROMs (Huawei/EMUI on Android 9-10) and for
large APKs the platform cannot re-parse the archive's signing block and
returns null even for a perfectly valid, untampered APK, while the
installed app's signers read back fine. That asymmetric "can't read the
archive's signers" was treated as "forged", bricking the in-app update
(observed: 6.1.0 -> 6.3.0, HUAWEI SEA-AL10, Android 10, ~194MB APK ->
"安装包完整性检查失败 - 安装不安全").

This signing-cert cross-check is defense-in-depth only: verifyASC already
proves the bytes are the authentic OneKey APK via GPG + SHA-256, and
Android's PackageInstaller re-verifies the signing certificate at install
time. So a genuine certificate MISMATCH is still hard-failed, but when the
signers are simply unavailable we now just log it and silently skip the
check instead of throwing. Normal devices are unchanged.

Claude-Session: https://claude.ai/code/session_01NwuZPQd7xBE8S7KFtdkT9Y
@huhuanming huhuanming force-pushed the fix/android-apk-verify-signature-unavailable branch from e50e815 to 93b9c4d Compare June 24, 2026 07:06
@huhuanming huhuanming changed the title fix(android): don't block APK update when archive signers are unreadable fix(android): don't block APK update when signing info is unavailable Jun 24, 2026
Add a selectedIcons prop end-to-end so UIKit owns the bottom-tab selection
visual instead of a JS round-trip:

- codegen spec + .mm prop bridge for selectedIcons
- Swift loadSelectedIconsFromSources / bakeTint(.alwaysOriginal) / selectedImage
  so iOS 26 Liquid Glass stops washing icons to one tint and the focused
  (solid) artwork swaps natively with the selection animation
- TabView passes unfocused icons as icons and focused icons as selectedIcons
  on iOS; Android keeps the focusedKey-driven array (no-op setSelectedIcons)
- activeTintColor/inactiveTintColor didSet rebuild so baked tints follow theme
- updateSelectedTab skips the redundant performWithoutAnimation re-set when
  UIKit already moved the selection (keeps the native capsule animation)

Ported from the app-monorepo patch-package patch (OK-54175).

Claude-Session: https://claude.ai/code/session_019KatVf3hQYnB4oESVYQ8AL
@huhuanming huhuanming merged commit a8be8ec into main Jun 25, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants