參考:
http://tech.meituan.com/android-apk-v2-signature-scheme.html
http://www.lxweimin.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的簽名方式
使用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.
新的簽名方案會在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.lxweimin.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
通過上圖可以看出新的應用簽名方案的驗證過程:
尋找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,從而實現獲取渠道信息的功能