Android 7.0中新簽名對多渠道打包的影響詳解
老簽名多渠道打包原理
前言
由于Android7.0發(fā)布了新的簽名機(jī)制,加強(qiáng)了簽名的加固,導(dǎo)致在新的簽名機(jī)制下無法通過美團(tuán)式的方式再繼續(xù)打多渠道包了。不過在說新的簽名機(jī)制對打包方案的
影響和為什么會影響我們原有的打包機(jī)制之前,需要先簡單理解下打包原理和簽名在整個(gè)打包過程中的作用。
Android打包流程
Android打包過程大致如圖所示,整個(gè)流程就是將Java代碼,資源文件以及第三方庫整合成一個(gè)Apk文件,并對整合后的文件進(jìn)行簽名和優(yōu)化對齊。整個(gè)過程可以簡
單分為以下幾個(gè)步驟:
- 資源預(yù)編譯 為每一個(gè)非assert資源生成一個(gè)ID并保存在一個(gè)R文件中。
- Java文件編譯 把手動編寫的Java文件和前面步驟生成的Java文件一起編譯成.class文件
- Dex文件生成 把前面生成的class文件和第三方庫的class文件一起整合成.dex文件,相當(dāng)于所有.class文件的索引表,可以通過這個(gè)文件找到每一個(gè).class文件
- 資源文件打包 對資源進(jìn)行大小進(jìn)行優(yōu)化,并把所有有ID的資源對應(yīng)的配置信息收錄生成resource.arsc文件中,相當(dāng)于資源的索引表。
- APK文件生成 把之前生成的.dex文件和resource.arsc文件以及資源文件(res文件,里面包含一些已編譯成二進(jìn)制的文件如布局文件等和一些未編譯成二進(jìn)制的文件如圖片等)和未分配ID的文件(assert文件)等整合成一個(gè)APk文件(特殊的.zip文件)。
- 簽名 對生成的APK進(jìn)行簽名,添加唯一標(biāo)識,從而保證能夠正常安裝和覆蓋安裝,不會被惡意覆蓋,以及說明APK的來源和擁有者。
- 對齊處理 對APK中一些資源的二進(jìn)制上的位置進(jìn)行調(diào)整,從而加快APk運(yùn)行時(shí)的速度。
APK生成的步驟大概就是這個(gè)樣子,我們不需要糾結(jié)一些細(xì)節(jié)上的實(shí)現(xiàn),只要大概了解這些流程就能理解后面我們打包方案的原理了。當(dāng)然,這么看會覺得APK
是一個(gè)很神奇的文件,能夠安裝并且運(yùn)行。其實(shí),APK只是一中比較特別的.zip文件而已,只是它可以被我們的Android機(jī)器識別并且安裝成一個(gè)應(yīng)用,我們可以把APK文件解壓出來看一下里面的內(nèi)容。
可以看到文件內(nèi)容和我們前面說的基本一致,接下來再看看最重要的一個(gè)文件夾,就是第三章圖里的文件,這些文件都在META-INF文件夾里,這就是我們在簽名過程中加入的文件來作為APK的唯一標(biāo)識。那么這對我們打包優(yōu)化來說有什么意義呢,這里先保留下懸念,待會兒來說。在了解這個(gè)之前必須先把簽名這件事情說清楚。
簽名的作用和原理
簽名的作用
Android App在開發(fā)時(shí)都有一個(gè)唯一的標(biāo)識,我們把它叫做包名,比如大客戶端的包名是com.Quanr,包名就像身份證號一樣,是和每一個(gè)人一一對應(yīng)的,在把App安裝時(shí)機(jī)器也是通過包名來識別應(yīng)用的,一個(gè)機(jī)器中不能存在兩個(gè)包名一樣的應(yīng)用,這就是App在機(jī)器中的唯一性。我們在給App升級的時(shí)候,比如覆蓋安裝,就是通過包名來進(jìn)行識別和對應(yīng)的覆蓋,這樣才能保證App可以順利升級而不會覆蓋了其他的App,同樣,別的App包名不同也無法覆蓋我們的App。雖然Android提供了一套包名識別機(jī)制,但僅有包名就可以了嗎。試想一下,如果別人用我們的包名新建一個(gè)App想要覆蓋我們的App亦或是不法分子破解我們的
App往里面添加一些自己的內(nèi)容,比如內(nèi)嵌廣告來牟利,把篡改過的App再發(fā)出去讓用戶覆蓋安裝,我們可能會受到巨大的損失。當(dāng)然這種事情是不會發(fā)生的,Google為每一個(gè)App增加了一個(gè)簽名機(jī)制,就像我們?nèi)ャy行辦理業(yè)務(wù),不但要提供身份證,還要簽字畫押,身份證號大家都可以看到,但簽字畫押只有自己才能做,別人是無法模仿的,App正是通過這種機(jī)制保證了自身的唯一性和安全性。
那么,簽名是如何做到這些的呢。
簽名的原理
對Apk簽名有好幾種工具,但原理都是大同小異的,這里拿signapk這個(gè)工具來說,對apk簽名只要用這個(gè)工具附帶一些參數(shù)以及我們的唯一的簽名文件就可以完成了,直接使用工具簽名是很簡單的,我們更需要關(guān)注的是它的原理和具體是怎么實(shí)現(xiàn)的,這樣才能幫助我們從中找出打渠道包的秘密。在使用簽名工具之前我們必須準(zhǔn)備好簽名要用的私鑰和公鑰(a–(私鑰)–>b–(公鑰)–>a,最好用圖片展示),然后再用簽名工具對apk簽名,之后簽名流程會在apk里新建META-INF文件夾并在里面生成三個(gè)文件,這三個(gè)文件就是簽名的關(guān)鍵和驗(yàn)證的依據(jù)。
從圖中可以看到三個(gè)文件分別是:
- MANIFEST.MF
- CERT.RSA
- CERT.SF
接下來說說這三個(gè)文件是怎么生成的。
MANIFEST.MF
先看看它的內(nèi)容,可以看到是一些Name對應(yīng)的SHA1的值,很容易就能知道這個(gè)文件保存的是每一個(gè)文件對應(yīng)的一個(gè)唯一的值。MANIIFEST.MF文件的功能就如剛才說的一樣,在對APK簽名的時(shí)候,首先會對每一個(gè)文件進(jìn)行數(shù)字編碼,生成一個(gè)唯一的SHA1的值,不同的文件內(nèi)容不一樣所對應(yīng)的SHA1的值也是不同的,所以如果有人篡改了文件內(nèi)容,那么相應(yīng)的SHA1的值也會發(fā)生變化。在對APK進(jìn)行簽名的時(shí)候檢查自己的每一個(gè)文件,并生成對應(yīng)的SHA1值,把這些內(nèi)容都保存在一個(gè)新建的MANIFEST.MF文件中,并把這個(gè)文件放到META-INF目錄下,就完成了第一個(gè)簽名文件的生成。
CERT.SF
在生成了一個(gè)MANIFEST.MF文件之后,就能記錄下我們每一個(gè)文件的唯一值,從而保證文件不被篡改,這樣雖然保證了MANIFEST中記錄文件的安全,但卻無法保證自身的安全,別人照樣可以修改原有文件之后生成對應(yīng)的SHA1值然后再修改MANIFEST文件,所以我們還要對MANIFEST進(jìn)行加固,從而保證安全性。在進(jìn)行完第一個(gè)文件生成后,簽名工具開始生成第二個(gè)文件了,這個(gè)文件就是CERT.RSA。在這個(gè)步驟里,對上一步生成的文件繼續(xù)進(jìn)行一次數(shù)字編碼,把結(jié)果保存在這個(gè)新生成了CERT.RSA文件的頭部,在繼續(xù)對MANIFEST.MF文件中各個(gè)屬性塊做一次數(shù)字編碼,存到到CERT.SF文件的一個(gè)屬性塊中。
CERT.RSA
這個(gè)文件都是二進(jìn)制的,生成完CERT.SF文件之后,我們用私鑰對CERT.SF進(jìn)行加密計(jì)算得出簽名,將得到的簽名和公鑰的數(shù)字證書的信息一起保存到CERT.RSA中,整個(gè)簽名過程就結(jié)束了。
下面再簡單敘述一下Apk安裝過程中的驗(yàn)證步驟,其實(shí)就是和生成簽名文件的步驟類似:
- 首先檢驗(yàn)Apk中的所有文件的數(shù)字編碼和MANIFEST.MF中的數(shù)字編碼一致
- 驗(yàn)證CERT.SF文件的簽名信息和CERT.RSA中的內(nèi)容是否一致
- MANIFEST.MF整個(gè)文件簽名在CERT.SF文件中頭屬性中的值是否匹配以及驗(yàn)證MANIFEST.MF文件中的各個(gè)屬性塊的簽名在CERT.SF文件中是否匹配
從上面的過程中,可以很明顯的發(fā)現(xiàn)一個(gè)問題,在這個(gè)過程中從來就沒有對META-INF里的任何文件進(jìn)行數(shù)字編碼和加密,因?yàn)檫@個(gè)文件夾是簽名時(shí)生成的,在生成第一個(gè)文件MANIFEST.MF時(shí)并沒有對這個(gè)文件夾里的任何文件進(jìn)行數(shù)字編碼,因?yàn)檫@個(gè)文件夾一定是空的,第二個(gè)文件是基于第一個(gè)文件生成的,第三個(gè)文件又是基于第二個(gè)生成的,所以整個(gè)過程中,這個(gè)META-INF文件夾幾乎是在控制范圍之外的。我們可以在里面添加一些文件從而躲過簽名這個(gè)過程。這就是美團(tuán)多渠道包方案的突破口。
美團(tuán)通過利用簽名原理來完成多渠道打包
通過前面打包過程的了解,可以知道想快速打多渠道包,就得跳過打包的階段直接想辦法對Apk文件進(jìn)行修改,但這得挑戰(zhàn)Android的簽名校驗(yàn)規(guī)則了,不過正好,通過剛才我們對簽名過程的分析,我們發(fā)現(xiàn)可以在META-INF文件夾里隨意添加文件從而躲過簽名規(guī)則的檢查,這時(shí)候新方案就孕育而生了,在打包生成了一個(gè)沒有渠道的Apk文件后,我們copy這個(gè)Apk并在在META-INF里添加一個(gè)文件,然后通過文件名來確定渠道號,不同的Apk里就在META-INF里添加不同的渠道名文件,即可確定不同的渠道了,之后要做的就是在我們需要渠道參數(shù)的時(shí)候直接去這個(gè)文件里拿就行了,完美的跳過了打包這個(gè)過程。那么這種方案的耗時(shí)呢?僅僅就是基于一個(gè)Apk文件的基礎(chǔ)上復(fù)制并插入一個(gè)文件而已,這樣的動作在高配的電腦里一分鐘可以做900次。所以,這時(shí)候打一個(gè)渠道包要4分鐘,打100個(gè)渠道包也只要四分鐘加一個(gè)小零頭,當(dāng)然,這還不是極限,如果有900個(gè)渠道的話,一個(gè)個(gè)渠道包打包需要900x4分鐘,美團(tuán)方案只要5分鐘,提高了好幾百倍的效率,可以說美團(tuán)方案在老簽名下是非常完美的。
新簽名方式對現(xiàn)有方案的影響
在Android 7.0 之后,Google為了增強(qiáng)簽名的安全性,采用了新的簽名驗(yàn)證規(guī)則,不是針對每個(gè)文件來進(jìn)行數(shù)字編碼了,如圖所示:
新的簽名方式是根據(jù)zip文件結(jié)構(gòu)來進(jìn)行簽名的,Apk文件本質(zhì)上就是一個(gè).zip文件,如圖所示,在被簽名前可以分為三塊內(nèi)容。
- 壓縮文件實(shí)體數(shù)據(jù) 包含所有的元素具體數(shù)據(jù)
- 核心目錄數(shù)據(jù) 包含所有元數(shù)據(jù)的相對偏移量
- 目錄結(jié)束標(biāo)志 包含目錄數(shù)據(jù)的偏移位置和相關(guān)目錄詳情記錄
下圖中藍(lán)色的部分代表Contents of ZIP entries,粉色的部分代表Central Directory。
File Entry表示一個(gè)文件實(shí)體,一個(gè)壓縮文件中有多個(gè)文件實(shí)體。
文件實(shí)體由一個(gè)頭部和文件數(shù)據(jù)組成(壓縮后的,壓縮算法在頭部有說明)
Central Directory由多個(gè)File header組成,每個(gè)File header都保存一個(gè)文件實(shí)體的偏移
文件最后由一個(gè)叫End of central directory的結(jié)構(gòu)結(jié)束。
再看看End of Central Directory的作用,它記錄了Central Directory相對于頭部的偏移位置,再看看我們的新簽名數(shù)據(jù)Apk Signing Block是放在Contents of ZIP entries和Central Directory之間的,它是根據(jù)未簽名的ZIP文件三個(gè)模塊的所有內(nèi)容進(jìn)行編碼簽名后產(chǎn)生的一個(gè)唯一的數(shù)據(jù),可以按照前面說的數(shù)字編碼來理解,這三塊任何內(nèi)容發(fā)生改變后所產(chǎn)生的這塊的數(shù)據(jù)都是不一致的,所以在簽名之后無法對Apk的任何內(nèi)容進(jìn)行修改,不過我們前面也沒修改過Apk簽名之外的內(nèi)容,所以這個(gè)時(shí)候是不是可以考慮修改Apk Signing Block這塊內(nèi)容呢,我們在后面再追加一個(gè)小尾巴。顯然這個(gè)方法也不行了,前面說過最后有一個(gè)叫End of Central Direcotry的部分,記錄著Central Direcotry相對與ZIP文件起始位置的偏移,正好APK Signing Block位于Central Direcotry前面,如果改變APK Signing Block的長度那么Central Direcotry相對于頭部的偏移就改變了,內(nèi)容就會和Endof Central Directory里記錄的不一樣,整個(gè)Apk包就被破壞了。那么是不是可以修改這個(gè)偏移呢,顯然不行,修改過這個(gè)偏移之后Apk Signing Block也會變,然后只有擁有簽名文件的開發(fā)者才能得到對的APK Signing Block數(shù)據(jù),想要篡改這個(gè)的人只能望洋興嘆了。這就是新簽名機(jī)制的作用原理。在這套新的機(jī)制下,我們老的簽名可能就要進(jìn)行適當(dāng)?shù)男薷牧恕?/p>
改進(jìn)方案的思路
前面說過了,我們新的打包方案在新的簽名機(jī)制下又要捉襟見肘了(當(dāng)然,如果你還采用老簽名的話那么就不需要考慮這個(gè)問題了),不過,Google有張良計(jì),我們還有過墻梯~
之前說過添加渠道包有好幾種方式:
- 直接修改代碼,一個(gè)渠道包改一次代碼,然后再打包
- 不直接修改代碼,放出一個(gè)渠道參數(shù)在打包之前動態(tài)改變?nèi)缓笤俅虬?/li>
- 修改打包完成后的文件通過跳過簽名校驗(yàn)加入渠道號
- 現(xiàn)在這三種方式都不行了,沒關(guān)系,我們還有第四中。
之前分析過,如果修改了zip文件的任何模塊內(nèi)容,APK Signing Block都會發(fā)生改變,從而無法再繞過簽名機(jī)制。
不過這個(gè)不要緊,簽名機(jī)制只是為了保障我們Apk的安全,我們顯然不是想惡意篡改App,我們可是開發(fā)者,手握著簽名文件的私鑰和公鑰,既然簽名機(jī)制繞不過去,那么我們就直接修改Apk包然后重新進(jìn)行簽名就行了。雖然這樣的效率沒有繞過簽名機(jī)制效率高,但相比于好幾分鐘的打包過程,這些時(shí)間也是可以接受的。一般重新簽名大概需要三四秒的時(shí)間,相對與我們四分鐘的打包流程,顯然還是可以接受和繼續(xù)使用的。
當(dāng)然,這只是基于我們簽名機(jī)制想出來的一個(gè)方案,之前和大家分析了打包和簽名的整個(gè)流程和機(jī)制,也許還有更好的方式可以從中挖掘出來,這就需要我們集思廣益了,仔細(xì)分析和思考這些流程和原理,也許你就能找出更好的解決方案來繼續(xù)優(yōu)化我們的打包方案~
總結(jié)
以上就是關(guān)于Android7.0新簽名對多渠道打包影響的全部內(nèi)容棩䍖,希望本文的內(nèi)容對給我Android開發(fā)者們能帶來一定的幫助,如果有疑問大家可以留言交流
相關(guān)文章
Android自定義控件之水平圓點(diǎn)加載進(jìn)度條
這篇文章主要為大家詳細(xì)介紹了Android自定義控件之水平圓點(diǎn)加載進(jìn)度條,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06基于Android實(shí)現(xiàn)一個(gè)簡易音樂播放器
在Android平臺上開發(fā)一個(gè)音樂播放器是一項(xiàng)常見的任務(wù),這涉及到對音頻文件的處理、用戶界面設(shè)計(jì)以及多媒體框架的運(yùn)用,本項(xiàng)目基于樣例代碼進(jìn)行擴(kuò)展,雖然功能相對簡單,但包含了Android音樂播放器開發(fā)的核心知識點(diǎn),需要的朋友可以參考下2024-08-08Android開發(fā)手冊TextView屬性實(shí)現(xiàn)效果盤點(diǎn)
這篇文章主要為大家介紹了Android開發(fā)手冊TextView屬性實(shí)現(xiàn)的效果盤點(diǎn)及使用示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06Android自定義指示器時(shí)間軸效果實(shí)例代碼詳解
指示器時(shí)間軸在外賣、購物類的APP里會經(jīng)常用到,效果大家都知道的差不多吧,下面小編通過實(shí)例代碼給大家分享Android自定義指示器時(shí)間軸效果,需要的朋友參考下吧2017-12-12RecyclerView使用payload實(shí)現(xiàn)局部刷新
這篇文章主要為大家詳細(xì)介紹了RecyclerView使用payload實(shí)現(xiàn)局部刷新,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10Android編程實(shí)現(xiàn)webview將網(wǎng)頁打包成apk的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)webview將網(wǎng)頁打包成apk的方法,以打包HTML5為例分析了webview打包apk的相關(guān)方法、屬性與事件操作技巧,需要的朋友可以參考下2017-08-08android開發(fā)教程之使用listview顯示qq聯(lián)系人列表
這篇文章主要介紹了android使用listview顯示qq聯(lián)系人列表的示例,需要的朋友可以參考下2014-02-02Android自定義View實(shí)現(xiàn)BMI指數(shù)條
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)BMI指數(shù)條,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-06-06