×

Android N Signature Scheme v2 渠道打包

96
小面包屑
2017.03.31 16:25* 字数 1388

参考:
http://tech.meituan.com/android-apk-v2-signature-scheme.html
http://www.jianshu.com/p/a6e7a01c6cad

APK signature scheme v2(官网如是说)

Android 7.0 引入一项新的应用签名方案 APK Signature Scheme v2,它能提供更快的应用安装时间和更多针对未授权 APK 文件更改的保护。在默认情况下,Android Studio 2.2 和 Android Plugin for Gradle 2.2 会使用 APK Signature Scheme v2 和传统签名方案来签署您的应用。
虽然我们建议您对您的应用采用 APK Signature Scheme v2,但这项新方案并非强制性的。如果您的应用在使用 APK Signature Scheme v2 时不能正确开发,您可以停用这项新方案。禁用过程会导致 Android Studio 2.2 和 Android Plugin for Gradle 2.2 仅使用传统签名方案来签署您的应用。要仅用传统方案签署,打开模块级 build.gradle
文件,然后将行 v2SigningEnabled false
添加到您的版本签名配置中:

  android {
    ...
    defaultConfig { ... }
    signingConfigs {
      release {
        storeFile file("myreleasekey.keystore")
        storePassword "password"
        keyAlias "MyReleaseKey"
        keyPassword "password"
        v2SigningEnabled false
      }
    }
  }

注意:如果您使用 APK Signature Scheme v2 签署您的应用,并对应用进行了进一步更改,则应用的签名将无效。出于这个原因,请在使用 APK Signature Scheme v2 签署您的应用之前、而非之后使用 zipalign
等工具。
如需了解详细信息,请阅读相关的 Android Studio 文档,这些文档介绍了如何在 Android Studio 中签署应用以及如何使用 Android Plugin for Gradle 为签署应用配置构建文件

android studio2.3的正式版之后,正式启用了V2的签名方式

Paste_Image.png

使用v2方式打包,7.0以下安装失败。
使用v1方式打包,7.0以及7.0以下的版本都没问题。

结论:单独使用V2签名的apk是不能在小于7.0的手机上安装的,会出现签名证书找不到的情况,为了防止出现这种情况,AS使用了可以同时选择两种签名方式
即:7.0以下使用V1的签名方式,7.0以后的就使用V2的签名方式

APK文件格式

apk 本身是个 zip 格式, 格式可以参考http://blog.sina.com.cn/s/blog_4c3591bd0100zzm6.html.

Paste_Image.png

新的签名方案会在ZIP文件格式的 Central Directory 区块所在文件位置的前面添加一个APK Signing Block区块,下面按照ZIP文件的格式来分析新应用签名方案签名后的APK包。

整个APK(ZIP文件格式)会被分为以下四个区块:

Contents of ZIP entries(from offset 0 until the start of APK Signing Block)
APK Signing Block
ZIP Central Directory
ZIP End of Central Directory

新应用签名方案的签名信息会被保存在区块2(APK Signing Block)中, 而区块1(Contents of ZIP entries)、区块3(ZIP Central Directory)、区块4(ZIP End of Central Directory)是受保护的,在签名后任何对区块1、3、4的修改都逃不过新的应用签名方案的检查。

这样的话,之前的美团打包方案就会有问题。
http://www.jianshu.com/p/ef186125dac4

新的应用签名方案下META-INF已经被列入了保护区了,向META-INF添加空文件的方案会对区块1、3、4都会有影响,新应用签名方案签署的应用经过我们旧的生成渠道包方案处理后,在安装时会报以下错误:

Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES: 
Failed to collect certificates from base.apk: META-INF/CERT.SF indicates base.apk is signed using APK Signature Scheme v2, 
but no such signature was found. Signature stripped?]

多渠道打包解决方案

1 、往APK中添加ZIP Comment

这种方法是根据zip格式核心目录的内容注释(Comment)做处理

         End of central directory record     

Offset  Bytes   Description 
0   4   End of central directory signature = 0x06054b50 核心目录结束标记(0x06054b50)
4   2   Number of this disk 当前磁盘编号
6   2   Disk where central directory starts 核心目录开始位置的磁盘编号
8   2   Number of central directory records on this disk    该磁盘上所记录的核心目录数量
10  2   Total number of central directory records   该磁盘上所记录的核心目录数量
12  4   Size of central directory (bytes)   核心目录的大小
16  4   Offset of start of central directory, relative to start of archive  核心目录开始位置相对于archive开始的位移
20  2   Comment length (n)  注释长度 (n)
22  n   Comment 注释内容

apk 默认情况下没有comment,所以 comment length的short 两个字节为 0,我们需要把这个值修改为我们的comment的长度,然后把comment追加到后边即可。

在gradle 中通过如下方式 disable scheme v2

signingConfigs {
    release {
        v2SigningEnabled false
    }
}   
2 、美团第一代打包工具walle
Paste_Image.png

通过上图可以看出新的应用签名方案的验证过程:

寻找APK Signing Block,如果能够找到,则进行验证,验证成功则继续进行安装,如果失败了则终止安装
如果未找到APK Signing Block,则执行原来的签名验证机制,也是验证成功则继续进行安装,如果失败了则终止安装

美团通过在APK Signing Block中扩展ID-VALUE来实现渠道包。
因为在源码当中,只存在一个ID-VALUE的判断

 if (id == APK_SIGNATURE_SCHEME_V2_BLOCK_ID) {return getByteBuffer(pairs, len - 4);}

而这个区域的其它 ID-VALUE 是被忽略的。
将渠道号放到里面,打包的时候就能绕过验证。

到这里为止一个新的渠道包生成方案逐步清晰了起来,下面是新一代渠道包生成工具的描述:

对新的应用签名方案生成的APK包中的ID-value进行扩展,提供自定义ID-value(渠道信息),并保存在APK中
而APK在安装过程中进行的签名校验,是忽略我们添加的这个ID-value的,这样就能正常安装了
在App运行阶段,可以通过ZIP的EOCD(End of central directory)、Central directory等结构中的信息(会涉及ZIP格式的相关知识,这里不做展开描述)找到我们自己添加的ID-value,从而实现获取渠道信息的功能

开发笔记
Web note ad 1