一款A(yù)ndroid APK的結(jié)構(gòu)構(gòu)成解析
作者:hockeyli,騰訊 PCG 客戶(hù)端開(kāi)發(fā)工程師
一、 APK 組成解析
在開(kāi)始解析 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)的類(lèi)名
看到上面的例子,可能有些人會(huì)拋出一個(gè)疑問(wèn)就是那我們?cè)趺创_定構(gòu)建中執(zhí)行的 task 具體對(duì)應(yīng)哪個(gè)類(lèi)呢,這里提供一個(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)名也都一起打印出來(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
歡迎點(diǎn)贊
到此這篇關(guān)于一款A(yù)ndroid APK的結(jié)構(gòu)構(gòu)成解析的文章就介紹到這了,更多相關(guān)Android apk 結(jié)構(gòu)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android中CountDownTimer類(lèi)詳解
本文詳細(xì)講解了Android中CountDownTimer類(lèi),文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-12-12Android 安全退出應(yīng)用程序的方法總結(jié)
這篇文章主要介紹了Android 安全退出應(yīng)用程序的方法總結(jié)的相關(guān)資料,需要的朋友可以參考下2017-03-03Android 自定義ProgressDialog進(jìn)度條對(duì)話框用法詳解
ProgressDialog為進(jìn)度對(duì)話框。android手機(jī)自帶的對(duì)話框顯得比較單一,我們可以通過(guò)ProgressDialog來(lái)自己定義對(duì)話框中將要顯示出什么東西2016-01-01Android雙擊返回鍵退出程序的實(shí)現(xiàn)方法
這篇文章主要介紹了Android雙擊返回鍵退出程序的實(shí)現(xiàn)方法,是Android程序開(kāi)發(fā)中非常具有實(shí)用價(jià)值的重要技巧,需要的朋友可以參考下2014-09-09利用Kotlin的協(xié)程實(shí)現(xiàn)簡(jiǎn)單的異步加載詳解
這篇文章主要給大家介紹了關(guān)于利用Kotlin的協(xié)程實(shí)現(xiàn)簡(jiǎn)單的異步加載的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-03-03Android實(shí)現(xiàn)淘寶購(gòu)物車(chē)
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)淘寶購(gòu)物車(chē),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05Presenting?Streams?in?Flutter小技巧
這篇文章主要為大家介紹了Presenting?Streams?in?Flutter小技巧示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12