第4章 签名块大小与包体积关系:签名数据存储结构归纳总结
你有没有想过,一个签名块居然能吃掉好几MB的包体积?我刚开始接触APK优化时也不信,直到有一天我发现一个release包比debug包大了3MB,排查到最后,罪魁祸手就是签名块里的“垃圾数据”。
说白了,签名块不是简单的一个签名值,它是一套复杂的容器结构。你签的每个证书、每条属性、甚至签名工具带的额外信息,都会被塞进这个块里。今天咱们就把这块结构彻底拆开,看看里面的每一层是怎么堆出来的。
签名块在APK中的位置
先看整体布局。APK本质上是个ZIP文件,在ZIP的Central Directory(中央目录)和End of Central Directory(EOCD)之间,Android插了一个“签名块”。
| APK布局 | 说明 |
|---|---|
| ZIP Local File Headers + File Data | 文件数据区 |
| APK Signing Block | 签名块(关键) |
| ZIP Central Directory | 中央目录 |
| EOCD | 结束记录 |
嗯,这里要注意:签名块并不是ZIP规范的一部分,完全是Android自己加塞进去的。所以在做ZIP对齐、压缩时,签名块的大小变化对整体包体积影响非常直接。
签名块内部结构剖析
签名块采用“ID-Value”对的形式存储。每个条目包含一个8字节的ID和一个长度可变的Value。整个块的结构如下:
+-----------------------------+
| Block Size (8 bytes) | ← 整个块长度(不包括这8字节)
+-----------------------------+
| ID-Value Pair #1 |
| +--------+----------+ |
| | ID (8B)| Value(L) | |
| +--------+----------+ |
| ID-Value Pair #2 |
| ... |
+-----------------------------+
| Block Magic (16 bytes) | ← 固定魔数
+-----------------------------+
| Block Size 副本 (8 bytes) |
+-----------------------------+
我习惯把这个结构称为“签名集装箱”。你想想,每个ID-Value对就像一件货物,集装箱本身还要有外皮(Block Size和Magic)。
V2/V3签名块数据格式
最常见的签名是V2和V3,它们对应不同的ID:
- V2签名ID: 0x7109871a
- V3签名ID: 0xf05368c0
在V2(APK Signature Scheme v2)中,Value内部是一个完整的签名块,包含多个signer块。每个signer又包含:
- signed data – 被签名的数据(包含digest、证书等)
- signatures – 实际的签名值(可能多个算法)
- public key – 公钥
我遇到过的一个坑:早期某个版本的signapk.jar(签名工具)会在每个signer里重复写入整个证书链,导致签名块体积飙升。后来Google官方修复了,但很多三方签名工具还在用旧版。
| 字段 | 大小范围 | 对体积影响 |
|---|---|---|
| 证书(X.509) | ~1-2KB | 每个signer一份,多证书叠加 |
| 签名值(RSA-2048) | 256字节 | 每次签名固定大小 |
| Digest(SHA-256) | 32字节 | 每个文件一个,文件数多时膨胀 |
| 自定义属性(ID: 0x427a…) | 不定 | 工具添加的额外信息,最容易忽略 |
你看,一个典型的V2签名块大概在几KB到几十KB。但如果你的APK文件很多(比如几千个),digest列表就会很长——这会直接撑大签名值里的signed data。
签名块大小的影响因素(总结)
- 证书数量和长度 – 每个signer带一个证书链(多级CA)。如果用了多个签名证书,体积翻倍。
- 签名算法选择的冗余 – 同时包含RSA、ECDSA、DSA多个签名,每个都占空间。
- 文件列表(digest数量) – 每个文件一个digest。几千个文件就有几万个字节。
- 签名工具附加数据 – 比如
apksigner默认不加额外信息,但有的渠道打包工具会注入渠道ID、版本戳等。 - 块对齐填充 – 某些情况下签名块需要4字节对齐,填充字节也会增加体积。
从上图你能直观看到:签名块不是孤立存在的,它夹在文件数据和ZIP结构之间。块内的每个ID-Value对都消耗真实字节。我个人习惯在打完渠道包后,用zipalign -c -v 4 apk.apk检查一下对齐情况,同时用apksigner verify --verbose看看签名块里到底塞了什么东西。
好了,这一章我们就把签名数据存储结构彻底理清了。你要记住:签名块的体积来源于证书、签名值、digest列表以及不可控的自定义数据。优化方向无非就是减少不必要的signer、精简证书链、压缩digest数量(减少APK文件数量)。