apk打包流程

aapt資源編譯

  1. 編譯assets目錄和res/raw目錄下的資源
  2. 編譯res目錄下的資源文件
  3. 給res目錄下的每個資源賦予一個資源ID,生成resource.arsc資源索引文件
  4. 解析並編譯AndroidMainifest.xml
  5. 資源打包成*.ap_,資源ID常量定義自R.java

資源索引

aapt給每一個非assets目錄的資源定義一個資源ID,它是一個4字節(byte = 32bit)的數字,格式是PPTTNNNN,PP代表資源所屬的包(package),TT代表資源的類型(Type),NNNN代表這個類型下面的資源名稱(Entry ID)。

  • Package ID相當於是一個命名空間,標定資源的來源。系統資源的命名空間,它的package ID等於0x01;自己的APP資源名稱空間,Package ID一般定義爲0x7f。
  • Type ID是指資源的類型ID。資源的類型都有animator、anim、color、drawable、layout、menu、raw、string和xml等等若干種,每一種都會被賦予一個ID。
  • Entry ID是指每一個資源在其所屬的資源類型中所出現的次序。

代碼編譯和打包

  • AIDL -> 生成對應的java接口
  • Javac -> 生成.class文件
  • dex-> 生成dex文件
  • APkBuilder:aapt打包好的資源、dex打包好的代碼文件、第三方庫資源和jar文件、native -> apk

簽名

v1簽名

對簽名後的apk進行解壓縮,在META-INF目錄下一般會有三個文件:MANIFEST.MF、CERT.SF和CERT.RSA三個文件,這裏用不同的證書和簽名方式得到的名字可能不同。

  • .MF文件:apk當中的原始文件信息用摘要算入如SHA1(或者SHA256)計算得到的摘要信息並用base64編碼保存,以及對應採用的摘要算法如SHA1(這個算法的特徵是不管多大的文件內容都能夠得到長度相同的摘要信息,但是不同的文件內容信息得到的摘要信息肯定不相同)
  • .SF文件:.MF文件的只要信息以及.MF文件中每個條目在用摘要算法計算得到的摘要信息,對這些內容使用base64編碼後保存
  • .RAS文件:存放證書信息、公鑰信息以及用私鑰對.SF文件的加密數據即簽名信息,這段數據是無法僞造的,除非你有私鑰,病外.RSA文件還記錄了所有的簽名算法等信息.

APK包在安裝的時候,是按照RSA->SF->MF的順序依次校驗的:**先用公鑰信息還原簽名信息,然後和.SF文件中的信息進行比對,然後用同樣的摘要算法對.MF文件裏的每一個條目計算對應的摘要信息,然後比對.MF是否一致。

缺點

  1. 在校驗的過程中需要解壓,因爲.MF文件的摘要信息是基於原始未壓縮的文件內容,因此在校驗的時候需要解壓出原始數據,而這個解壓操作無疑是耗時的。
  2. apk包的完整性校驗不夠強。這裏可以看到如果我們在apk簽名後,如果對apk包中沒有涉及到原始文件內容的數據塊做修改那麼這層校驗機制就會失效。

V2簽名

簡單來說,v2簽名模式在原先apk塊中添加了一個新的塊(簽名塊),新的塊存儲了簽名、摘要、簽名算法、證書鏈和一些額外的屬性等。這個塊有特定的格式。

apk的格式簽名後變成了下面4個部分

   Local file header 1   //第一部分開始
     compressed data
   data descriptor(可選)
   .....
   Local file header n
     compressed data
   data descriptor(可選)   //第一部分結束

   APK Signning Block      //簽名塊

   Central directory header1 //第二部分開始
   ....
   Central directory headern //第二部分結束
   End Of Central Directory  //第三部分

其中第三部分有一個偏移值直接指向了第二部分的開始位置,而每個第二部分如Central directory header1 … Central directory headern的有一個便宜字段指向了其中對應的第一部分。

Central directory header1--->Local file header1
...
Central directory headern--->Local file headern

簽名塊包括對apk第一部分、第二部分和第三部分的二進制內容做加密保護,摘要算法以及簽名算法。簽名塊本身不做加密,這裏需要特殊注意的是由於第三部分包含了對第二部分的引用偏移,因此如果簽名塊做了改變,比如在簽名過程中增加了一種簽名算法,或者增加簽名者等信息就會導致這個偏移發生改變,因此在算摘要信息的時候需要剔除這個音粗要以第三部分對簽名塊的偏移來做計算。

v2簽名塊格式

接下來我們看看具體的apk簽名塊格式,改格式分爲4個部分:

  • 分塊長度
  • v2模式塊
  • 分塊長度
  • 固定magic值


怎樣找到v2分塊的位置:ZIP中央結尾記錄->中央目錄其實偏移量->固定magic值,然後就可以定位v2分塊的位置。

摘要計算過程

v2簽名塊負責保護第1、3、4部分的完整性,以及第二部分包含的APK簽名方案 v2分塊中的signed data分塊的完整性。第1、3、4部分的完整性是通過內容摘要來保護的,這些摘要保存在signed data分塊中,而signed data分塊的完整性是通過簽名保證的。下面開計算摘要的過程

第1、3和4部分的摘要要採用以下的計算方法

  1. 拆分chunk:將每個部分拆分成爲多個大小爲1MB大小的chunk,最後一個chunk可能小於1MB,之所以要分塊,是爲了可以通過並行計算摘要以加快計算速度。
  2. 計算chunk摘要:字節0xa5+塊的長度(字節數)+塊的內容進行計算
  3. 計算整體摘要:字節0x5a+chunk數+塊的摘要的連接(按塊在APK中的順序)進行計算。

從上面我們可以知道v2模式塊有點類似於

zipalign

  • 對簽名後的apk進行對齊處理,在apk中所有的未壓縮文件,如圖片、raw資源,按照4字節來對齊。
  • 其實就是使用空間換時間,CPU是按字節讀取內存的,內存對齊可以避免讀取某個類型數據時需要二次讀取。對於Linux系統,CPU就可以直接用mmap()來存取數據。因此,在加載資源時,系統不需要把全部數據都加載到RAM,降低了內存佔用和電量的消耗,提高了資源存取效率。

多渠道打包

  • Flavor + BuildType
  • 在assets目錄添加配置文件
  • META-INF
  • v2簽名的多渠道打包
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章