
在 Android 开发中我们经常会遇到 APK 签名相关的问题比如keytool-printcert-jarfileapp-release.apk结果却提示不是已签名的 jar 文件很多人第一反应是APK 没签名其实不一定。这个问题通常和 Android APK 签名方案 v1、v2、v3、v4 的区别 有关。Android APK 签名并不是只有一种方式。随着 Android 系统版本演进APK 签名方案从最早的 JAR 签名逐步发展到 APK 整包签名、支持密钥轮换再到支持增量安装的 v4 签名。本文系统介绍 Android APK Signature Scheme v1、v2、v3、v4 的区别以及在实际项目中该如何理解和排查。一、APK 签名是用来做什么的Android 要求应用安装包必须经过数字签名。签名主要有几个作用证明 APK 来源系统可以通过签名证书判断这个 APK 是否来自同一个开发者。保护 APK 完整性如果 APK 被篡改签名校验会失败。判断应用是否允许覆盖安装同一个 packageName 的 App更新安装时必须签名一致否则系统会拒绝安装。支持应用之间的信任关系比如 sharedUserId、signature 权限、应用升级、组件访问控制等都可能依赖签名证书。简单来说packageName 决定“这是哪个 App”签名证书决定“这个 App 是不是同一个开发者发布的”二、v1JAR 签名v1 是 Android 最早使用的 APK 签名方案本质上是 JAR 签名。APK 本身是一个 ZIP 文件结构早期 Android 直接沿用了 Java JAR 的签名机制。1. v1 签名的位置v1 签名信息通常位于 APK 内部的META-INF/MANIFEST.MF META-INF/CERT.SF META-INF/CERT.RSA或者META-INF/*.RSA META-INF/*.DSA META-INF/*.EC这也是为什么keytool -printcert -jarfile xxx.apk能读取 v1 签名证书。因为对 keytool 来说这个 APK 就像一个签名过的 JAR 文件。2. v1 校验什么v1 签名主要校验 APK 内部每个文件的摘要。它会记录每个文件的 hash然后通过签名文件证明这些 hash 没有被篡改。大致可以理解为APK 内的文件 A - hashAPK 内的文件 B - hashAPK 内的文件 C - hash然后对这些 hash 信息进行签名3. v1 的优点v1 最大优点是兼容性好它支持非常老的 Android 系统。如果你的 App 还要支持 Android 6.0 或更低版本那么通常需要保留 v1 签名。4. v1 的缺点v1 的缺点也很明显安全性较弱校验速度较慢不能完整保护 APK 整体结构因为 v1 关注的是 ZIP 内部文件而不是整个 APK 文件本身所以它对 APK 整体结构的保护不够完整。这也是后来 Android 引入 v2 签名的重要原因。三、v2APK Signature Scheme v2v2 签名从 Android 7.0也就是 API 24 开始引入。它不再把 APK 当成普通 JAR 来签而是引入了专门的 APK Signing Block。官方文档也明确说明Android 支持的应用签名方案包括基于 JAR 的 v1以及 Android 7.0 引入的 APK Signature Scheme v2。(Android Open Source Project)1. v2 签名的位置v2 签名信息位于 APK 文件中的APK Signing Block它不是放在 META-INF/*.RSA 里的。所以如果一个 APK 只有 v2/v3 签名没有 v1 签名那么执行keytool-printcert-jarfileapp-release.apk就可能出现不是已签名的 jar 文件这并不代表 APK 没签名只是说明它没有传统 JAR 签名或者 keytool 无法识别它的 APK 签名块。2. v2 校验什么v2 签名校验的是 APK 的整体内容。它比 v1 更严格能覆盖 APK 文件的大部分整体结构。可以简单理解为v1校验 APK 里面的文件v2校验 APK 这个整体文件所以如果 APK 被重新压缩、插入内容、修改结构v2 签名通常会失效。3. v2 的优点v2 的优势主要有两个更安全安装校验更快因为它按 APK 整体进行校验系统安装时可以更高效地完成签名验证。4. v2 的兼容性v2 从 Android 7.0 开始支持。也就是说Android 7.0 及以上可以识别 v2Android 7.0 以下不识别 v2如果你的 App 还要支持 Android 6.0 或更低版本不能只使用 v2通常还需要保留 v1。四、v3APK Signature Scheme v3v3 签名从 Android 9.0也就是 API 28 开始引入。官方说明中提到v3 的整体格式和 v2 很相似但增加了 supported SDK versions 和 proof-of-rotation 结构。(Android Open Source Project)简单来说v3 ≈ v2 签名证书轮换能力1. v3 解决什么问题v3 最重要的能力是支持 key rotation也就是签名证书轮换在 Android 早期一个 App 一旦发布签名证书几乎不能更换。因为系统判断 App 更新是否合法核心依据就是新 APK 的 packageName 是否一致新 APK 的签名证书是否和旧 APK 一致如果签名证书变了系统通常会认为这不是同一个 App从而拒绝覆盖安装。这就导致一个问题如果老签名 key 泄露、过期、算法不够安全怎么办v3 就是为了解决这类长期维护问题而设计的。2. proof-of-rotation 是什么proof-of-rotation 可以理解为“签名历史证明”。它告诉系统旧签名证书 A新签名证书 B它们之间存在合法的轮换关系这样系统就能知道虽然现在签名变成了 B但它是从 A 合法升级过来的所以仍然可以认为是同一个 AppAndroid 9 的官方说明中也提到v3 支持包含 proof-of-rotation record用于签名证书轮换。(Android Developers)3. v3 的兼容性v3 从 Android 9.0 开始支持。Android 9.0 及以上可以识别 v3Android 9.0 以下不识别 v3因此在实际项目中v3 通常不会单独存在而是和 v1/v2 一起使用。五、v4APK Signature Scheme v4v4 是一个比较特殊的签名方案。它不是为了替代 v1/v2/v3而是主要服务于增量安装ADB incremental install大型 APK 快速部署Android 11 引入了 v4 签名。官方说明中提到v4 会生成一个单独的签名文件文件名类似app.apk.idsig并且 v4 不会修改 APK 本身。(Android Developers)1. v4 签名在哪里和 v1/v2/v3 不同v4 签名通常不直接写在 APK 内部而是在 APK 外部生成一个独立文件app-release.apk app-release.apk.idsigAndroid 开源项目文档也说明v4 签名存储在独立的 .idsig 文件中并且 v4 需要配合 v2 或 v3 签名使用。(Android Open Source Project)2. v4 有什么用v4 主要用于增量安装。比如一个大型 APK在开发调试时不一定需要完整传输整个 APK 文件而可以边传输、边校验、边安装。这对于大型 App 或游戏非常有帮助。常见场景包括adbinstall--incrementalapp-release.apk或者 Android Studio / AGP 在调试大型 APK 时使用增量安装能力。3. v4 是必须的吗对大多数普通 App 来说v4 不是必须关注的重点。日常发布 APK 时真正核心的是v1v2v3v4 更多是安装优化、调试优化相关的辅助签名方案。六、v1、v2、v3、v4 对比总结签名方案引入版本签名位置主要作用是否保护整个 APK典型用途v1Android 早期META-INF/*.RSAJAR/ZIP 文件签名不完整兼容老系统v2Android 7.0APK Signing BlockAPK 整体签名是更安全、更快安装v3Android 9.0APK Signing Blockv2 key rotation是支持签名证书轮换v4Android 11独立 .idsig 文件增量安装辅助校验ADB incremental install七、为什么 keytool 会提示“不是已签名的 jar 文件”假设你执行keytool-printcert-jarfile/Users/xx/Desktop/app-release.apk然后看到不是已签名的 jar 文件这通常说明这个 APK 没有 v1/JAR 签名但它仍然可能有v2 签名v3 签名所以这个报错不能直接等价于“APK 没签名”。更准确的理解应该是keytool 只能识别传统 JAR 签名现代 APK 可能主要使用 v2/v3 签名所以 keytool 看不到。八、正确查看 APK 签名的方式查看 APK 签名推荐使用 Android SDK Build Tools 里的 apksigner。命令如下apksigner verify--verbose--print-certs app-release.apk如果系统找不到 apksigner可以使用完整路径~/Library/Android/sdk/build-tools/35.0.0/apksigner verify--verbose--print-certs app-release.apk或者先查看本机 build-tools 版本ls~/Library/Android/sdk/build-tools然后替换成对应版本例如~/Library/Android/sdk/build-tools/34.0.0/apksigner verify--verbose--print-certs app-release.apk官方 apksigner 文档也说明apksigner verify 支持 --print-certs 参数用于显示 APK 签名证书信息。(Android Developers)九、apksigner 输出怎么看执行命令apksigner verify--verbose--print-certs app-release.apk可能会看到类似输出Verifies Verified using v1 scheme (JAR signing): false Verified using v2 scheme (APK Signature Scheme v2): true Verified using v3 scheme (APK Signature Scheme v3): true Verified using v4 scheme (APK Signature Scheme v4): false Signer #1 certificate DN: CNxxx, OUxxx, Oxxx Signer #1 certificate SHA-256 digest: A1:B2:C3:... Signer #1 certificate SHA-1 digest: 11:22:33:... Signer #1 certificate MD5 digest: AA:BB:CC:...重点看几个地方。1. VerifiesVerifies表示 APK 签名校验通过。如果没有通过说明 APK 可能未签名、被篡改或者签名结构存在问题。2. v1/v2/v3/v4 状态示例Verified using v1 scheme (JAR signing): false Verified using v2 scheme (APK Signature Scheme v2): true Verified using v3 scheme (APK Signature Scheme v3): true这表示没有 v1 签名有 v2 签名有 v3 签名这种 APK 是正常签名 APK。只不过因为没有 v1所以keytool -printcert -jarfile读不到。3. SHA-256 digest最重要的是Signer #1 certificate SHA-256 digest这个是签名证书的 SHA-256 指纹。如果你要比较两个 APK 是否使用同一个签名证书可以分别执行apksigner verify --print-certs app1.apk apksigner verify --print-certs app2.apk然后对比Signer #1 certificate SHA-256 digest。如果 SHA-256 一致说明两个 APK 使用的是同一套签名证书。十、AAB 和 APK 的签名关系现在 Google Play 常见上传格式是 AAB也就是 Android App Bundle。而官网、企业分发、三方渠道常见格式是 APK。这两者格式不同Google Play通常上传 AAB官网分发通常提供 APK但判断它们是否属于同一个 App关键不是 AAB 还是 APK而是packageName 是否一致最终安装到设备上的 APK 签名证书是否一致举例Google Play 上的 App packageName com.example.app官网 APK packageName com.example.app签名证书 SHA-256 一致那它们就是同一个应用身份。十一、实际项目中应该怎么配置一般来说现代 Android 项目不需要开发者手动选择复杂的签名组合Android Gradle Plugin 会根据 minSdk、targetSdk、构建配置自动处理。但理解规则依然很重要。1. 如果还支持 Android 6.0 或更低建议保留v1 v2 v3原因是 Android 7.0 以下不识别 v2/v3。如果只签 v2/v3老系统可能无法安装。2. 如果最低只支持 Android 7.0可以使用v2 v3因为 Android 7.0 开始支持 v2。此时没有 v1 也可以正常安装到 Android 7.0 及以上设备。3. 如果最低只支持 Android 9.0理论上可以使用v3但实际项目中通常仍会保留 v2/v3以保证更好的兼容性和工具链支持。4. v4 要不要开启普通发布不用特别关注 v4。v4 更多用于增量安装ADB incremental install大型 APK 调试提速AGP 中也提供了 v1/v2/v3/v4 签名开关例如 enableV1Signing、enableV2Signing、enableV3Signing、enableV4Signing。官方 Gradle API 文档中也列出了这些签名配置项。(Android Developers)十二、常见问题Q1keytool 报“不是已签名的 jar 文件”是不是 APK 没签名不一定。更可能是APK 没有 v1/JAR 签名但有 v2/v3 签名。建议使用以下命令确认apksigner verify--verbose--print-certs app-release.apkQ2怎么判断两个 APK 是不是同一个签名分别执行命令apksigner verify --print-certs app1.apk apksigner verify --print-certs app2.apk对比Signer #1 certificate SHA-256 digest一致就是同一个签名证书。Q3APK 只有 v2/v3没有 v1正常吗正常。前提是你的最低支持系统版本不需要 Android 7.0 以下。如果还要支持 Android 6.0 或更低建议保留 v1。Q4v3 是不是比 v2 更安全所以可以只用 v3不建议这样理解。v3 的核心价值不是简单替代 v2而是在 v2 基础上增加签名证书轮换能力。实际项目中通常是组合使用而不是只开某一个。Q5v4 会影响正常用户安装吗一般不会。v4 主要用于增量安装场景普通 APK 分发主要还是看 v1/v2/v3。十三、总结Android APK 签名方案可以这样理解v1老方案JAR 签名兼容老系统v2现代方案APK 整体签名更安全、更快v3v2 增强版支持签名证书轮换v4辅助方案服务于增量安装如果遇到keytool-printcert-jarfilexxx.apk提示不是已签名的 jar 文件不要立刻判断 APK 没签名。正确做法是使用apksigner verify--verbose--print-certs xxx.apk只要看到Verifies Verified using v2 scheme: true Verified using v3 scheme: true就说明 APK 是有签名的。现代 Android APK 签名排查中apksigner 才是更准确的工具keytool -jarfile只适合查看传统 v1/JAR 签名。