新聞中心
一、 APK 組成解析
在開始解析 Android 構(gòu)建流程之前,我們先來(lái)看下構(gòu)建的最終產(chǎn)物 APK 的整體組成:

APK 主要由五個(gè)部分組成,分別是:
- Dex:.class 文件處理后的產(chǎn)物,Android 系統(tǒng)的可執(zhí)行文件
- Resource:資源文件,主要包括 layout、drawable、animator,通過(guò) R.XXX.id 引用
- Assets:資源文件,通過(guò) AssetManager 進(jìn)行加載
- Library:so 庫(kù)存放目錄
- META-INF:APK 簽名有關(guān)的信息
1.1 Apk 分析工具
工欲善其事,必先利其器,既然想分析 APK 必然少不了好用的工具。
① Android Studio 自帶的 APK 分析器
通過(guò) APK 分析器,我們可以完成這些操作:
- 查看 APK 中文件(如 DEX 和 Android 資源文件)的絕對(duì)大小和相對(duì)大小
- 了解 DEX 文件的組成
- 快速查看 APK 中文件(如 AndroidManifest.xml)的最終版本
- 對(duì)兩個(gè) APK 進(jìn)行并排比較
② ClassyShark 可以做為 AS 自帶 APK 分析器的補(bǔ)充,幫我們分析 dex 中的詳細(xì)數(shù)據(jù),以及查看 APK 中的總方法數(shù)以及各個(gè)模塊的方法數(shù)分布。
1.2 Dex 知識(shí)點(diǎn)拓展
當(dāng)我們?cè)?Android 查看一個(gè) APK 的時(shí)候,可以看到右上角有 Defined Methods 和 Referenced Methods,但大多數(shù)人可能不知道這兩者的區(qū)別,這里簡(jiǎn)單說(shuō)明下:
Defined Methods:在這個(gè) Dex 中定義的方法;Referenced Methods:Defined Methods 以及 Defined Methods 引用到的方法。
Android 有 64K 引用限制,當(dāng) type_ids、method_ids 或者 field_ids 超過(guò) 65536(64 * 1024)的時(shí)候,需要進(jìn)行 dex 分包,為了 Dex 的數(shù)量盡可能少,我們需要盡量實(shí)現(xiàn)「Dex 信息有效率」的提升。
- Dex 信息有效率 = Defined Methods 數(shù)量 / Referenced Methods 數(shù)量
二、 構(gòu)建源碼導(dǎo)讀
當(dāng)我們用 Android Studio 進(jìn)行安裝包構(gòu)建的時(shí)候,會(huì)發(fā)現(xiàn)其實(shí)是運(yùn)行了一連串的 Task,也就是說(shuō)其實(shí)是這些 task 的配合,最終構(gòu)建出我們的 APK 的。
2.1 源碼引入
如果我們想更了解 Android 的構(gòu)建流程,對(duì)于相關(guān)的源碼肯定是要有所了解的。那我們?nèi)绾慰吹竭@些 Task 相關(guān)的源碼呢,我們知道 Android 是用 Gradle 進(jìn)行構(gòu)建的,也就意味著這些 task 其實(shí)都是放在 Gradle 中,我們想看 Gradle 中源碼的話,可以在 build.gradle 將 Gradle 進(jìn)行編譯。
- compileOnly "com.android.tools.build:gradle:3.0.1"
編譯完之后,可以在 ApplicationTaskManager#createTasksForVariantScope 中找到創(chuàng)建這些 Task 相關(guān)的代碼,也就意味著順藤摸瓜找到這些 Task 的真正實(shí)現(xiàn)邏輯。
2.2 BuildConfig Task 詳解
這里以 BuildConfig 文件的生成為例,來(lái)梳理下如何查看某個(gè) task 的代碼邏輯。
生成 BuildConfig 文件,是通過(guò) ApplicationTaskManager 中通過(guò) createBuildConfigTask 來(lái)創(chuàng)建對(duì)應(yīng)的 task。
順著代碼邏輯,我們找到最終真正實(shí)現(xiàn)這個(gè)邏輯的是:GenerateBuildConfig 這個(gè) task,GenerateBuildConfig 是繼承自 BaseTask,這里有個(gè)小技巧是,Task 中真正的執(zhí)行邏輯都是在帶著 @TaskAction 注解的方法上的,所以我們能很快找到對(duì)應(yīng)的 generate() 方法??梢钥吹缴?BuildConfig 整體的邏輯還是比較簡(jiǎn)單的,其實(shí)就是將 build.gradle 中自帶的屬性以及我們自定義的屬性進(jìn)行讀取,然后通過(guò) JavaWriter 生成對(duì)應(yīng)的 BuildConfig 文件。
2.3 獲取所有 task 對(duì)應(yīng)的類名
看到上面的例子,可能有些人會(huì)拋出一個(gè)疑問(wèn)就是那我們?cè)趺创_定構(gòu)建中執(zhí)行的 task 具體對(duì)應(yīng)哪個(gè)類呢,這里提供一個(gè)小技巧,其實(shí)我們可以在 taskGraph 構(gòu)建完成之后,將所有 task name 以及對(duì)應(yīng)的 class 進(jìn)行打印。例如在 build.gradle 中加入這個(gè)代碼之后,我們?cè)谶\(yùn)行的時(shí)候,就會(huì)把 task 所對(duì)應(yīng)的類名也都一起打印出來(lái)。
三、構(gòu)建流程梳理
可以看到 Android 構(gòu)建中會(huì)涉及到多個(gè)工具,我們可以通過(guò) open $ANDROID_HOME/build-tools 來(lái)查看相關(guān)的構(gòu)建工具。
四、手動(dòng)構(gòu)建 APK
最后我們通過(guò)命令行來(lái)手動(dòng)打包一個(gè)可執(zhí)行的 APK,能讓我們對(duì) APK 構(gòu)建的理解更加深入。首先需要準(zhǔn)備下 代碼、資源文件、AndroidManifest 這些構(gòu)建 APK 的必要文件。
① 通過(guò) aapt2 compile 將 res 資源編譯成 .flat 的二進(jìn)制文件:
- aapt2 compile -o build/res.zip --dir res
② 通過(guò) aapt2 link 將 .flat 和 AndroidManifest 進(jìn)行連接,轉(zhuǎn)化成不包含 dex 的 apk 和 R.java:
- aapt2 link build/res.zip -I $ANDROID_HOME/platforms/android-30/android.jar --java build --manifest AndroidManifest.xml -o build/app-debug.apk
③ 通過(guò) javac 將 Java 文件編譯成 .class 文件:
- javac -d build -cp $ANDROID_HOME/platforms/android-30/android.jar com/**/**/**/*.java
④ 通過(guò) d8 將 .class 文件轉(zhuǎn)化成 dex 文件:
- d8 --output build/ --lib $ANDROID_HOME/platforms/android-30/android.jar build/com/tencent/hockeyli/androidbuild/*.class
⑤ 合并 dex ?件和資源?件:
- zip -j build/app-debug.apk build/classes.dex
⑥ 對(duì) apk 通過(guò) apksigner 進(jìn)行簽名:
- apksigner sign -ks ~/.android/debug.keystore build/appdebug.apk
當(dāng)前文章:一款A(yù)PK是怎么誕生的?
網(wǎng)頁(yè)URL:http://www.dlmjj.cn/article/dhdcjsh.html


咨詢
建站咨詢
