签名方案V1:基于JAR签名对包体积的影响
V1 签名方案,说白了就是用传统 JAR 签名的方式给 APK 打上指纹。Android 从最初就支持它,直到现在 AGP 依然保留着兼容。我刚开始做 Android 时,项目里所有 APK 都只用 V1 签名,那时候包体积还没人太在意。直到后来搞模块化拆分,发现一个几十兆的 APK 里,签名文件竟然能占到好几 MB——这才把我注意力拉过来。
V1 到底怎么影响体积?其实它就是在 APK 的 META-INF/ 目录下塞了一堆签名相关文件。每次签名,AGP 都会重新生成这些文件,它们会随着 APK 的增大而膨胀。跟我来细看。
V1 签名文件全家桶
| 文件 | 说明 | 体积占比特征 |
|---|---|---|
MANIFEST.MF |
清单文件,列出 APK 内所有文件的 SHA-256 摘要 | 随 APK 内文件数量线性增长 |
CERT.SF |
对 MANIFEST.MF 中每条摘要再做签名 | 体积约为 MANIFEST.MF 的 80%–90% |
CERT.RSA |
包含开发者公钥和签名证书 | 通常 1~3 KB 固定大小 |
嗯,这里要注意:MANIFEST.MF 和 CERT.SF 才是体积大头。我记得有个项目里模块化分了 40 多个 feature,每个 feature 又包含大量 drawable、layout 和编译后的类。最终 V1 签名文件的体积达到了 2.1 MB——而那个 APK 总共才 28 MB。你想想看,7% 就这么白白浪费在签名上。
为什么 V1 签名这么“能吃”
核心原因其实很简单:V1 签名要对 APK 里的每一个文件单独计算哈希并记录。哪怕你只改了 res 里一张图,重新签名后所有文件的摘要都会重新算一遍——但这不是体积变大的关键。关键在 条目数。
模块化项目里,每个模块编译后的输出都会被打包进 APK。文件数量动不动就几千甚至上万。每个文件在 MANIFEST.MF 里占一行,格式像这样:
Name: res/drawable-mdpi/ic_launcher.png
SHA-256-Digest: A4s7...==
一行平均大约 60~80 字节。假设你有 8000 个文件,光 MANIFEST.MF 就接近 600 KB。CERT.SF 再来个 500 KB,加上 RSA,直逼 1.2 MB。这还不算资源混淆或压缩造成的玄学差异。
我踩过的坑
resConfigs 筛选语言,签名文件直接砍掉了 1.1 MB。
所以我的建议是:如果你还在用 V1 签名(比如 targetSdkVersion < 24),一定要关注一下 APK 内部的文件总数。可以用下面这条命令快速查看:
unzip -l app-release.apk | grep -c "Name:"
运行后会输出 MANIFEST.MF 中的条目数量。再乘以 70(粗略估算),就是你签名文件的大致体积(字节)。
V1 签名对包体积的影响随 APK 大小变化的实测数据
我们在几个典型模块化项目里做了测试,记录如下:
| APK 总大小 | 文件总数 | V1 签名文件体积 | 占比 | 备注 |
|---|---|---|---|---|
| 12.6 MB | 3,200 | 0.52 MB | 4.1% | 小型模块化项目 |
| 28.3 MB | 7,800 | 1.34 MB | 4.7% | 中型项目(含 3 个 feature 模块) |
| 55.0 MB | 15,200 | 2.65 MB | 4.8% | 大型项目(12 个模块,含大量 native lib) |
| 92.1 MB | 22,000 | 3.82 MB | 4.1% | 超大型,包含多架构动态库 |
你会发现比例基本稳定在 4%~5% 之间。但别忘了,这 4%~5% 是纯“签名开销”,完全不包含任何功能代码。如果你 APK 本身只有 20 MB,近 1 MB 就花在了签名上——我个人觉得,这代价在模块化项目里是值得重视的。
能不能去掉 V1?
当然可以。Android 7.0(API 24)以上,系统优先使用 V2 签名。如果你的 minSdkVersion >= 24,完全可以把 V1 关掉:
android {
defaultConfig {
// ...
}
signingConfigs {
release {
// ...
enableV1Signing false
enableV2Signing true
}
}
}
这样打包后,META-INF/ 里就只剩下 MANIFEST.MF 和 APK SIGNATURE.SF(V2 格式),体积能降 80% 以上。但注意:一旦关闭 V1,你的 APK 就无法安装在 Android 7.0 以下的设备上。所以如果你还要兼顾老机型,就不得不保留 V1。
MANIFEST.MF 做后期优化(比如剔除空文件条目)。不过 AGP 自身没有提供消除空白条目的开关,需要借助工具脚本手动清理。一张图看懂 V1 签名对包体积的影响
下面这张图梳理了 V1 签名文件如何挤占 APK 空间。注意每个模块的文件数量最终都会在 MANIFEST.MF 中体现出来。