Android 10 报 INSTALL_PARSE_FAILED_NO_CERTIFICATES 如何排查?
结论:先查 v2 内容摘要校验失败
日志表明,Android 10 设备在验证 APK Signature Scheme v2 时,计算出的内容摘要与签名中记录的摘要不一致。现有信息不足以确定根因,也不能据此认定“JDK 或 Gradle 越新,就越不支持旧 Android”。
关键错误是:
using APK Signature Scheme v2: SHA-256 digest of contents did not verify
这里的 INSTALL_PARSE_FAILED_NO_CERTIFICATES 不代表 APK 完全没有证书。设备已经进入 v2 验证流程,失败发生在内容完整性检查阶段。
Android 从 7.0(API 24)起就支持 v2,因此 Android 10 可以验证 v2 签名。当前的 v1: false 不能直接解释这个错误,也不应把启用 v1 作为首选修复方式。AOSP v2 签名说明
这些版本分别影响什么?
| 配置 | 主要作用 |
|---|---|
| Gradle JVM | 在开发机上运行 Gradle 和构建插件 |
| Project SDK 中的 JBR/JDK | IDE 项目使用的 Java SDK 配置,不能仅凭它判断 Gradle 实际使用的 JVM |
| Gradle version | 构建工具版本,需要与 JDK、Android Gradle Plugin 配套 |
| Android Gradle Plugin(AGP) | Android 构建插件,参与编译、DEX 转换、打包和签名流程 |
compileSdk = 36 | 编译时使用的 Android API 范围 |
minSdk = 28 | 应用声明支持的最低 Android API level |
较高的 compileSdk 可以与较低的 minSdk 配合使用。调用较新 API 时仍需处理版本兼容问题,但 compileSdk = 36 本身不会把最低安装版本变成 API 36。构建 JVM 与应用在设备上的运行环境也要分开看。Android 构建中的 Java 版本说明
Gradle 的兼容表列明,从 Gradle 8.10 开始支持使用 Java 23 运行。因此,不能仅凭版本号判定 Gradle 8.13 + JDK 23 不兼容。但这也不代表所有 Android 插件都兼容该组合;目前还缺少 AGP 版本。Gradle Java 兼容表
第一步:固定安装的 APK,并明确验证 API 29
先确保验证和安装使用同一个文件,期间不要重新构建或覆盖它。可以把 APK 复制到单独目录,再执行:
/home/USER/Android/Sdk/build-tools/36.1.0/apksigner verify \
--verbose \
--print-certs \
--min-sdk-version 29 \
--max-sdk-version 29 \
app-debug.apk
这两个参数将工具的验证范围限定为 API 29,让诊断条件更明确。默认验证会参考 APK Manifest 中的最低版本。apksigner 参数说明
如果仍显示 Verifies,只能说明该文件通过了这套主机工具的验证。由于设备上的验证结果不同,还需要检查传输后的文件和设备环境。
原输出中的 System::loadLibrary、--enable-native-access 警告来自开发机上运行工具的 Java 环境。该次命令最终报告了 Verifies,没有证据表明这些警告导致了设备端安装失败。
第二步:检查传输路径和文件完整性
原日志显示使用了 streamed install。可以先尝试非流式安装:
adb install --no-streaming app-debug.apk
--no-streaming 会先推送 APK,再单独调用 Package Manager 安装,可以用来对比安装路径。ADB 参数说明
如果仍然失败,可以手动推送并比较文件摘要。以下命令适用于主机和设备均提供 sha256sum 的情况:
sha256sum app-debug.apk
adb push app-debug.apk /data/local/tmp/debug-signature-check.apk
adb shell sha256sum /data/local/tmp/debug-signature-check.apk
adb shell pm install /data/local/tmp/debug-signature-check.apk
比较两次输出中的 SHA-256 值:
- 不一致:优先检查是否选错文件、构建是否覆盖了文件,以及传输或存储是否有问题。
- 一致但安装失败:继续调查该 APK 的生成过程和设备验证环境。
- 仅非流式安装成功:优先检查 Platform-Tools、连接和流式安装路径。
这里比较的是整个 APK 文件的摘要。apksigner --print-certs 输出的证书 SHA-256 指纹用于标识证书,不能代替 APK 文件完整性比较。
第三步:检查签名后的处理流程
v2 签名保护 APK 的相关内容和 ZIP 结构。签名后再次修改受保护内容,会使签名失效。检查是否有脚本、插件或外部工具在签名后重新压缩、替换资源、插入文件或执行 zipalign;手动处理时,zipalign 应在签名之前运行。apksigner 签名注意事项
可以直接用 Gradle 输出目录中的 debug APK 做对照,跳过额外的复制加工和重打包流程。如果原始产物能安装,而后处理产物失败,应修正后处理与签名的顺序。
第四步:核对实际构建环境,逐项做对照
先在项目根目录检查命令行构建环境:
./gradlew --version
同时确认 IDE 的 Gradle JVM 设置。终端构建与 IDE 构建可能使用不同的 JDK,还应检查是否配置了 org.gradle.java.home 或 Gradle Daemon JVM criteria。Gradle JVM 配置说明
接着补齐 AGP 版本,按该版本的兼容要求选择 Gradle 和 JDK。不要同时更改 JDK、Gradle、AGP 和 compileSdk;否则即使恢复正常,也无法判断是哪一项产生了影响。
切换构建 JDK 后,可以停止旧 daemon 并重新构建。以下示例假设应用模块名为 app:
./gradlew --stop
./gradlew --version
./gradlew :app:assembleDebug --no-build-cache --rerun-tasks
常见产物位置是:
app/build/outputs/apk/debug/app-debug.apk
对新产物重新执行签名验证和安装测试。只有单独更改某个变量后,失败能够稳定消失或重现,才有依据进一步定位工具链问题。
如果只有这台 Android 10 设备失败
使用同一份、文件摘要一致的 APK,在另一台 API 29 设备或 API 29 模拟器上对比。API 35 模拟器安装成功,尚不能区分 API level 差异与特定设备系统差异。
如果只有原设备失败,记录其型号、系统版本和 build fingerprint,并在复现后获取日志:
adb shell getprop ro.build.fingerprint
adb logcat -d -v threadtime > install-log.txt
如果多个 API 29 环境均失败,则更值得围绕该构建产物及工具链制作最小复现。目前缺少 AGP 版本、其他 API 29 环境的结果和传输前后的文件摘要,不能进一步断言具体缺陷。
开发低 API level 应用时,应保留所需的 minSdk,使用彼此兼容的 AGP、Gradle 和 JDK,并在最低支持版本及关键中间版本上验证。针对这次错误,优先确认 APK 完整性和可复现条件;降低 compileSdk、重新生成 debug keystore 或添加 v1 签名,都没有足够证据作为直接解决方案。
备注:内容仅供参考。
