Android APK 签名基础:V1、V2、V3、V4 一网打尽
做 Android 开发这些年,签名这事儿我打交道最多。别小看它,签名的选择直接影响你包体积、增量更新、甚至用户隐私合规。今天咱们就把 V1、V2、V3、V4 这四个签名方案掰开揉碎,讲清楚它们到底是什么、怎么选。
一句话先记住:签名不是加文件,而是保护 APK 完整性和来源可信度。你装的每个 App 都经过签名验证,否则系统直接拒绝安装。
V1 签名——最古老,也最兼容
V1 是 Android 1.0 时代就有的方案。说白了,它把签名信息放在 APK 文件内的 META-INF/ 目录下,用三个文件搞定:MANIFEST.MF、CERT.SF、CERT.RSA。
- 工作方式:对 APK 里的每个非签名文件单独计算 SHA1 摘要,存到
MANIFEST.MF;再用私钥对摘要签名,生成CERT.SF和CERT.RSA。 - 优点:兼容 Android 7.0 以下所有设备,老项目迁移无压力。
- 缺点:只保护了文件内容,没保护 APK 文件结构。恶意程序可以解压、修改、重新打包后,只要保留
META-INF/里的签名文件,就能绕过校验。
我曾踩过坑:有一次接入第三方 SDK,对方给的 AAR 里混了 V1 签名。我在 Android 11 设备上测试一切正常,结果发布后被用户反馈安装失败——因为 SDK 里的单个文件被系统安全策略识别为可篡改。最后逼着对方升级签名方案才解决。
V2 签名——全文件保护,更安全
Android 7.0(API 24)引入了 V2 签名。它把签名信息嵌入到 APK 的 ZIP 中央目录之前,对整包做签名,包括 ZIP 条目(文件列表、压缩方式、偏移量等)都纳入校验。
- 校验逻辑:安装时解析 ZIP 结构,找到签名块,验证整个包是否被篡改。
- 优点:
- 阻止了中间人修改 ZIP 结构,安全性提升明显。
- 与 V1 兼容,可以同时使用两种签名(回退校验)。
- 缺点:对增量更新不友好。APK 签名块修改后,整个包的哈希都变了,导致差分补丁不能再做。
你想想看,如果你的 App 要做增量更新(比如 Google Play 的 apk-expansion-files 或国内厂商的分包),V2 签名会增加包体积——因为差分工具根本没法利用原来的签名块了。我个人习惯是:只要目标设备是 Android 8.0 以上,只打 V2 签名就能省点体积。
V3 签名——密钥轮换,生命周期更灵活
V3 在 Android 9.0(API 28)推出。它最大的亮点是:支持密钥轮换。什么意思?就是你的 App 可以换签名密钥,但系统仍然信任它。
实现原理:签名块里链式存储了历史签名信息,每个新密钥签名时附带上一轮的签名证明。系统安装时会沿着链条验证整个信任链。
| 特性 | V2 | V3 |
|---|---|---|
| 密钥轮换 | 不支持 | 支持(通过签名链) |
| 兼容性 | Android 7.0+ | Android 9.0+ |
| 包体积影响 | 增加少量元数据(约 1~2 KB) | 增加签名链长度(约 2~4 KB / 每轮) |
我建议:如果你的 App 生命周期超过三年,或者有换包名、换企业主体等场景,现在就启用 V3 签名。密钥轮换策略能让你在未来优雅过渡——否则你只能发新包,旧用户要卸载重装。
V4 签名——专为增量更新而生
V4 签名是 Android 11 开始支持的。它不直接替换 V2/V3,而是额外生成一个独立的签名文件(.idsig),用来支持流式安装和更精准的增量补丁。
- 核心特性:签名信息分离,系统可以在解压过程中逐块验证,不用等全部下载完。
- 对包体积的影响:V4 签名本身不改变 APK 内容,签名文件单独存储。但 AGP(Android Gradle Plugin)在打 Release 包时默认会生成
.idsig文件,如果你不小心把它连带上传到应用商店,就会白白多出几百 KB 的体积。
注意:很多团队在 CI/CD 流水线里没清理 .idsig 文件,结果发现 APK 包体积莫名大了 200~500 KB。我建议你在打包脚本里显式排除 *.idsig,或者用 --no-v4-signature 参数关闭 V4 生成(除非你明确需要流式安装)。
实战对比:怎么选?
下面这张表格覆盖了主流场景下的推荐配置。记住,签名方案可以叠加——AGP 默认同时打 V1+V2+V3 是安全的,但你得根据目标设备版本做取舍。
| 场景 | 推荐方案 | 包体积影响 | 说明 |
|---|---|---|---|
| 兼容所有设备(minSdk <24) | V1 + V2 | 增加约 5 KB | V1 保证旧设备,V2 保证安全性 |
| 仅支持 Android 7.0+ | 仅 V2 | 减少约 3 KB(无 META-INF) | 去掉 V1 能省一个目录 |
| 支持密钥轮换 | V2 + V3 | 增加约 4~6 KB | V3 签名链有额外开销 |
| 需要增量更新(流式) | V2 + V3 + V4 | 注意排除 .idsig | V4 只生成独立文件,不嵌入 APK |
AGP 中如何控制签名配置?
在 build.gradle.kts 或 build.gradle 中,你可以通过 signingConfig 块精确控制启用哪些签名方案。下面是一个典型生产配置:
android {
signingConfigs {
create("release") {
keyAlias = "my-alias"
keyPassword = "****"
storeFile = file("my-key.jks")
storePassword = "****"
// 默认启用 V1+V2,我们可以显式关闭 V1 只留 V2 和 V3
enableV1Signing = false
enableV2Signing = true
enableV3Signing = true
enableV4Signing = false // 关闭 V4 避免生成 .idsig
}
}
buildTypes {
release {
signingConfig = signingConfigs.getByName("release")
}
}
}
这段代码里我故意关了 V1 和 V4。为什么?因为我的 minSdk 是 24,V1 根本没用了。V4 呢,我不做流式安装,而且 CI 脚本经常忘删 .idsig,干脆在源头掐掉。
注意:如果你关闭了 V1 签名,但 minSdk < 24,那么 Android 6.0 及以下设备会直接拒绝安装!所以别图省体积就不加 V1——除非你确定用户群没有低版本设备。我曾经给一个企业 App 关掉 V1 后,老板的手机(Android 5.1)死活装不上,最后被骂了一顿……
总结一下
签名方案没有“最新最好”的说法,只有“适不适合你的场景”。V1 兼容但弱安全,V2 安全但不支持密钥轮换,V3 灵活但有体积开销,V4 是增量更新利器但也带来额外文件。我的习惯是:
- 目标 SDK < 24:V1 + V2
- minSdk = 24~28:V2 + V3
- minSdk ≥ 29:仅 V2 + V3(或加 V4 按需)