Markdown版本筆記 | 個人GitHub首頁 | 個人博客 | 個人微信 | 個人郵箱 |
---|---|---|---|---|
MyAndroidBlogs | baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
Android APK 打包流程 MDjava
參考android
Android的包文件APK分爲兩個部分:代碼和資源
,因此打包方面也分爲資源打包和代碼打包兩個方面,這篇文章就來分析資源和代碼的編譯打包原理。git
Android打包流程詳圖:github
APK總體的的打包流程以下圖所示:數組
具體說來:微信
AAPT
工具進行資源文件(包括AndroidManifest.xml、佈局文件、各類xml資源等)的打包,生成R.java文件。AIDL
工具處理AIDL文件,生成相應的Java文件。Javac
工具編譯項目源碼,生成Class文件。DX
工具將全部的Class文件轉換成DEX文件,該過程主要完成Java字節碼轉換成Dalvik字節碼,壓縮常量池以及清除冗餘信息等工做。ApkBuilder
工具將資源文件、DEX文件打包生成APK文件。KeyStore
對生成的APK文件進行簽名。ZipAlign
工具進行對齊處理,對齊的過程就是將APK文件中全部的資源文件舉例文件的起始距離都偏移4字節的整數倍,這樣經過內存映射訪問APK文件的速度會更快。上述流程都是Android Studio在編譯時調用各類編譯命令
自動完成的,具體說來,以下所示:數據結構
一、建立Android工程。app
android create project \
-n packageTest2 \
-a MainActivity \
-k com.package.test2 \
-t android-23 \
-p ./PackageTest2ide
二、編譯R文件函數
aapt package \
-f \
-J ./gen \
-M ./AndroidManifest.xml \
-S ./res/ \
-I /Users/RadAsm/Library/AndroidSDK/sdk/platforms/android-23/android.jar
三、編譯源代碼文件
javac -source 1.6 \
-target 1.6 \
-cp /Users/RadAsm/Library/AndroidSDK/sdk/platforms/android-23/android.jar \
./src/com/packtest/test1/MainActivity.java ./src/com/packtest/test1/R.java \
-d ./gen/classes
四、編譯DEX文件
dx --dex \
--verbose \
--output ./gen/dex/packtest1.dex
./gen/classes/
五、生成APK文件
aapt package
-f \
-J ./gen \
-M ./AndroidManifest.xml \
-S ./res/ \
-I /Users/RadAsm/Library/AndroidSDK/sdk/platforms/android-23/android.jar \
-F ./output/res.apk
六、APK文件對齊
zipalign -v -p 4 packagetest_unsigned.apk packagetest_aligned_unsigned.apk
七、APK簽名
apksigner sign --ks my-release-key.jks my-app.apk
以上即是APK打包的整個流程,咱們再來總結一下:
理解了總體的流程,咱們再來看看具體的細節。
在分析資源的編譯和打包以前,咱們先來了解一下Android程序包裏有哪些資源。
咱們知道Android應用程序的設計也是代碼與資源相分離
的,Android的資源文件能夠分爲兩大類:
assets:assets資源放在主工程assets目錄下,它裏面保存一些原始的文件,能夠以任何方式來進行組織,這些文件最終會原封不動的被打包進APK文件中。
獲取asset資源也十分簡單,以下所示:
InputStream is = getAssets.open("fileName");
res:res資源放在主工程的res目錄下,這類資源通常都會在編譯階段生成一個資源ID供咱們使用。
res資源包含了咱們開發中使用的各類資源,具體說來:
這些資源的含義你們應該都很熟悉,這裏就再也不贅述。
上述9種類型的資源文件,除了raw
類型資源,以及Bitmap文件的drawable
類型資源以外,其它的資源文件均爲文本格式的XML
文件,它們在打包的過程當中,會被編譯成二進制格式的XML文件。這些二進制格式的XML文件分別有一個字符串資源池,用來保存文件中引用到的每個字符串,包括XML元素標籤、屬性名稱、屬性值,以及其它的一切文本值所使用到的字符串。這樣原來在文本格式的XML文件中的每個放置字符串的地方在二進制格式的XML文件中都被替換成一個索引到字符串資源池的整數值,這寫整數值統一保存在
R.java
類中,R.java會和其餘源文件一塊兒編譯到APK中去。
前面咱們提到xml編寫的Android資源文件都會編譯成二進制格式的xml文件,資源的打包都是由AAPT
工具來完成的,資源打包主要有如下流程:
AndroidManifest.xml
,得到應用程序的包名稱,建立資源表。R.java
中。AaptAssets
對象,收集當前須要編譯的資源文件,收集到的資源保存在AaptAssets對象對象中。ResourceTable
中去,用於最終生成資源描述文件resources.arsc
。values
類資源,這類資源包括數組、顏色、尺寸、字符串等值。resources.arsc
。每一個Android項目裏都有有一個R.java文件,以下所示:
public final class R { //... public static final class anim { public static final int abc_fade_in=0x7f010000; } public static final class attr { public static final int actionBarDivider=0x7f020000; } public static final class string { public static final int actionBarDivider=0x7f020000; } //... }
每一個資源項後的整數就是資源ID,資源ID是一個4字節的無符整數,以下所示:
上面提到,最終生成的是資源索引表resources.arsc
,Android正是利用這個索引表根據資源ID進行資源的查找,爲不一樣語言、不一樣地區、不一樣設備提供相對應的最佳資源。查找是經過Resources和AssetManger來完成的,這個咱們下面會講。
resources.arsc 是一個編譯後的二進制文件,在Android Stduio裏打開之後是這樣的,以下所示:
能夠看到resources.arsc裏存放了各種資源的索引參數和配置信息。
resources.arsc的文件格式以下所示:
注:整個文件都是有一系列chuck(塊)構成的,chuck是整個文件的劃分單位,每一個模塊都是一個chuck,chuck最前面是一個ResChunk_header的結構體,用來描述整個chunk的信息,更多關於索引表格式的細節,能夠查閱源碼:
resources.arsc 索引表從上至下文件格式依次爲:
資源包也被劃分爲如下幾個部分:
從這裏能夠看到resources.arsc索引表存在不少常量池,常量池的使用目的也很明顯,就是提供資源的複用率,減小resources.arsc索引表的體積,提升索引效率。
Android APK是如何來的呢?
懷着這個問題去查資料,發現了下邊這張圖。
解壓一個普通的apk文件後,解壓出來的文件包括:
MANIFEST.MF
文件:版本號以及每個文件的哈希值(BASE64),包括資源文件。這個是對每一個文件的總體進行SHA1(hash)。CERT.SF
:這個是對每一個文件的頭3行進行SHA1 hash。CERT.RSA
:這個文件保存了簽名和公鑰證書。使用aapt來打包res資源文件,生成R.java、resources.arsc和res文件(二進制 & 非二進制如res/raw和pic保持原樣)
AIDL,Android接口定義語言,Android提供的IPC的一種獨特實現。
這個階段處理.aidl文件,生成對應的Java接口文件。
經過Java Compiler編譯R.java、Java接口文件、Java源文件,生成.class文件。
經過dex命令,將.class文件和第三方庫中的.class文件處理生成classes.dex。
將classes.dex
、resources.arsc
、res
文件夾(res/raw資源被原裝不動地打包進APK以外,其它的資源都會被編譯或者處理)、Other Resources(assets
文件夾)、AndroidManifest.xml
打包成apk文件。
對apk進行簽名,能夠進行Debug和Release 簽名。
release mode 下使用 aipalign 進行align,即對簽名後的apk進行對齊處理。
Zipalign是一個android平臺上整理APK文件的工具,它對apk中未壓縮的數據進行4字節對齊,對齊後就可使用mmap
函數讀取文件,能夠像讀取內存同樣對普通文件進行操做。若是沒有4字節對齊,就必須顯式的讀取,這樣比較緩慢而且會耗費額外的內存。
在 Android SDK 中包含一個名爲 zipalign
的工具,它可以對打包後的 app 進行優化。 其位於 SDK 的 \build-tools\23.0.2\zipalign.exe
目錄下
2019-2-18