Android APK 各签名方案(v1 / v2 / v3 / v3.1 / v4)工作原理与作用

0. 一图速览(签名覆盖与"签名块")

APK 结构(末尾)

javascript 复制代码
... [文件内容区] ... | APK Signing Block | ZIP Central Directory | EOCD
                         ^ 仅 v2+ / v3 / v3.1 存在
  • v1(JAR) :逐个文件计算摘要,写进 META-INF/(MANIFEST.MF/.SF/ .RSA)。不覆盖 ZIP 元数据;安装校验要逐条目解压校验。
  • v2+(v2 / v3 / v3.1) :在 Central Directory 前 插入"APK Signing Block",对除签名块本身外的全包字节 分块哈希并签名,任何对包体/ZIP 元数据的改动都会使签名失效,校验更快。

1. v1(JAR 签名)------逐文件签名,兼容老设备

工作原理(验证链)

  1. 校验 META-INF/.SF 与 .RSA/DSA/EC 的关系(证书 + 对 .SF 的签名)。

  2. .SF 引用 MANIFEST.MF 中的各条目摘要;MANIFEST.MF 里记录**每个 ZIP 条目(解压前或后按实现)**的摘要。

  3. 逐条目比对摘要,未列入清单的条目不受保护,ZIP 元数据也不受保护。

作用与局限

  • 作用:确证开发者身份;支撑 Android 6.0 及以下 的安装。

  • 局限:攻击面大且校验慢(需要解析大量"尚未信任"的 ZIP 结构并解压比对),不能发现"仅改 ZIP 目录/对齐"的篡改。

官方因此在 Android 7.0 引入 v2 以提升完整性与性能。


2. v2(APK Signature Scheme v2)------整包分块签名,快且更牢

签什么

  • APK Signing Block 中保存 v2 签名数据;对除签名块外的几乎整包 按块(典型 1MB)做摘要,再对摘要集签名。改动任何字节或 ZIP 元数据都会破坏签名

怎么验

  • 安装器把 APK 当成整体 blob 校验(而非逐条目),因此显著加快

作用

  • 强完整性 + 快校验;并通过在 v1 元数据里声明"此 APK 也有 v2 签名",防降级(剥离 v2 仅按 v1 验)

3. v3(APK Signature Scheme v3)------在 v2 基础上加入"密钥轮换"

新增能力

  • 在签名数据里加入:

    • minSdk / maxSdk 元信息;

    • Proof-of-Rotation(签名谱系) :一条"旧证书 → 新证书 ..."的单链 ,声明"新证书继承旧证书的信任"。这让应用安全更换签名证书而不破坏依赖"签名相同"判断的系统行为(签名级权限、签名比较、历史共享等)。

验证与优先级

  • Android 9+:先验 v3,失败再回退 v2,再回退 v1(老设备看不见 v3)。

限制

  • 多签者发布不支持 (Google Play 也不发布多证书签名应用);v3 是单链轮换模型,不是任意图结构。

4. v3.1(Android 13+)------"定向生效"的轮换修复

要点

  • v3.1 签名数据与 v3 内容等价 ,但放在新的 Block ID 下:只有 Android 13+ 识别 ;旧系统会忽略 v3.1 块、继续使用 v3 块中的原签名 。这样就能在 13+ 切换到新密钥,同时不触发旧系统的历史兼容问题。

典型用法

  • 同一 APK 同时携带:

    • v3 块:老密钥,给 Android 12− 使用;
    • v3.1 块:新密钥,给 Android 13+ 使用。
  • 构建工具支持设置轮换生效的最小 SDK(--rotation-min-sdk-version)。


5. v4(Android 11+)------增量/流式安装的"旁路签名"

签什么与放哪

  • 生成独立的 *.apk.idsig 文件(不改 APK 本体 ),内容基于整包字节的 Merkle 哈希树(与 fs-verity 结构一致)。

怎么用

  • ADB/安装器可用它做流式/增量验证 (如 adb install --incremental)。设备/环境不支持时会回退普通安装。v4 需要配套 v2 或 v3 才能安装。

作用

  • 明显加速大 APK的开发安装与分发验证,不改变 v2/v3 的完整性保障职责。

6. 平台支持与选择建议

平台识别

  • < Android 7.0 :只认 v1

  • Android 7.0--8.x :优先 v2;无 v2 则回退 v1。

  • Android 9+ :优先 v3 → v2 → v1。

  • Android 13+ :还能识别 v3.1 (定向轮换);Android 11+ 支持 v4 增量安装。

配置策略(发布面广)

  • 需要兼容老设备:v1 + v2 + v3 ;计划在 13+ 轮换密钥再加 v3.1 ;开发/大包按需加 v4

7. 工程实操

7.1 Gradle(AGP)开关示例

arduino 复制代码
android {
  signingConfigs {
    release {
      // 兼容旧机就开 v1;现代发布至少 v2+v3
      v1SigningEnabled true
      v2SigningEnabled true
      v3SigningEnabled true
      v4SigningEnabled true // 需要增量安装/流式分发时开启
    }
  }
}

(AGP 具体行为以版本为准;底层仍由 apksigner 完成签名与校验策略。)

7.2apksigner常用命令

  • 签名与校验
arduino 复制代码
apksigner sign --ks release.jks app.apk
apksigner verify -v --print-certs app.apk
  • 密钥轮换(生成谱系 + 设定最小生效 SDK;33 即 13+ 触发 v3.1)
css 复制代码
# 生成/更新轮换谱系(lineage)
apksigner rotate --out lineage.sig --old-signer --ks old.jks \
                 --new-signer --ks new.jks

# 使用旧+新签名,附带谱系;指定轮换最小 SDK
apksigner sign --ks old.jks --next-signer --ks new.jks \
  --lineage lineage.sig --rotation-min-sdk-version 33 app.apk

(apksigner 会根据 rotation-min-sdk-version 选择写入 v3 还是 v3.1 块。)

7.3 v4 增量安装(开发提速)

bash 复制代码
# 先生成 idsig(AGP/adb 新版可自动生成)
adb install --incremental app.apk   # 需要同目录下 app.apk.idsig

(设备/工具不支持则回退普通安装。)


8. 常见坑与排障

  • 签后又改包 :v2+/v3 把整包当 blob 签名;zipalign/二次压缩/改注释/重排目录 都会破坏签名。务必"先 zipalign,后 apksigner" (AGP 已处理)。
  • 只签 v2 不带 v1 :在 7.0 以下无法安装(如还需兼容老机,务必带 v1)。
  • 轮换后旧系统出兼容问题 :用 v3.1(仅 13+ 生效)+ --rotation-min-sdk-version,让旧系统继续沿用旧密钥,13+ 才切换。
  • 多证书发布 :Android 9+ v3 文档明确不支持多签者,Play 也不发布多证书签名的 App。
  • 为何 v2 更安全 :因为 APK Signing Block 靠近末尾,覆盖(除签名块外的)所有字节+ZIP 元数据;相比 v1,能发现"只改 ZIP 中央目录/EOCD"的篡改且校验更快。

9. 结论与落地建议

  • 默认组合:v2 + v3;需要兼容 6.0− 再加 v1;计划 13+ 轮换钥时加 v3.1;大包/开发提速按需 v4。

  • 流程纪律 :构建顺序先对齐后签名;签名后禁止再改 APK;使用 apksigner verify -v 做发布前机型范围校验。

  • 密钥治理 :提前规划 proof-of-rotation ,并把 SHA-256 指纹同步到外部依赖(如 App Links 的 assetlinks.json 等)。

需要的话,我可以把这份说明转成你们团队的 发布自检清单 (含 Gradle 片段、CI 步骤、apksigner 命令与轮换 SOP),或根据你们 minSdk / 目标市场 / 是否计划换钥 直接给出最小变更建议。

相关推荐
南北是北北3 小时前
Activity的五种启动模式的具体使用场景详解
面试
疯狂踩坑人4 小时前
【面试系列】万字长文,速通TCP、HTTP(s)、DNS、CDN、websocket、SSE
前端·面试
小时前端4 小时前
前端稳定性:你的应用经得起一场“混沌演练”吗?
前端·面试
绝无仅有5 小时前
某短视频大厂的真实面试解析与总结(一)
后端·面试·github
JavaGuide5 小时前
中兴开奖了,拿到了SSP!
后端·面试
绝无仅有5 小时前
腾讯MySQL面试深度解析:索引、事务与高可用实践 (二)
后端·面试·github
沐怡旸19 小时前
【穿越Effective C++】条款7:为多态基类声明virtual析构函数——C++多态资源管理的基石
c++·面试