一、概述
什么是App的打包流程?
答:App的打包流程是指通過把資源(圖片、文本)、源代碼等資源打包成一個apk的過程。
了解打包流程能干什么事情?
通過了解打包流程我們可以對app打包的過程進行干涉,例如:1.在熱更新項目中我們可以干涉R.java中資源id的生成來防止宿主App和插件App資源沖突。2.我們可以在編譯前通過注解的形式生成輔助類從而優化代碼量和代碼結構(ButterKnife,Digger).3.通過javac把源代碼編譯成class文件后,在生成dex前我們可以對class文件進行干涉,動態的生成class文件(無痕埋點)。
下面就來看一下App的打包流程具體是怎樣的。
二、打包流程
我借用包建強的《Android插件化開發》中的一張圖來說明下
首先說下aapt是個什么東西?aapt是android中的資源打包工具,打包資源就用它。
下面看看打包流程的每一步都做了什么:
1.aapt把resources目錄下的資源生成R.java文件 ,並為AndroidManifest.xml生成Manifest.java類。
2.aidl把項目中自定義的aidl文件生成對應的java類。
3.JavaCompiler把所有的Java源文件編譯成class文件,包括:aapt生成的、aidl生成的、項目中自有的java源文件
4.使用proguard混淆,並生成一個proguardMapping.xml文件(可選項:可以混淆也可以不混淆)
5.使用dex工具把所有的class文件生成.dex文件
6.使用aapt資源打包工具把resources、assets目錄下的資源打包成一個_ap文件
7.使用apkbuilder把所有的dex、_ap文件、AndroidManifest.xml文件打包成一個未簽名的apk
8.使用jarsinger生成一個簽名過的apk包
9.使用zipalign工具對要發布的apk文件進行對齊操作,以便在運行時節約內存。
以上就是生成一個Apk包需要經歷的過程,大致可以分為9步。
三、修改aapt
假設你的項目正在使用插件化做熱修復,你的項目可以簡單的分為:宿主App、插件1、插件2、插件3四部分。而每個部分的資源都不一樣。如果要把插件中的資源合並到宿主中就不得不考慮一個問題,那就是資源沖突的問題。一旦資源沖突app就加載不到想要的資源。怎么辦?不着急,我們先來看看R.java的構成
public final class R { private R() {} public static final class attr { private attr() {} public static final int alpha = 0x7f020027; public static final int font = 0x7f020082; public static final int fontProviderAuthority = 0x7f020084; public static final int fontProviderCerts = 0x7f020085; public static final int fontProviderFetchStrategy = 0x7f020086; public static final int fontProviderFetchTimeout = 0x7f020087; public static final int fontProviderPackage = 0x7f020088; public static final int fontProviderQuery = 0x7f020089; public static final int fontStyle = 0x7f02008a; public static final int fontVariationSettings = 0x7f02008b; public static final int fontWeight = 0x7f02008c; public static final int ttcIndex = 0x7f020142; }
resources目錄下的每一個資源都會對應一個資源ID。默認情況下資源的開頭都是0x7f。
而資源id的構成分為三部分:
1.PackageId:apk包id,默認為0x7f
2.TypeId:資源類型Id ,例如:drawable、attar、string等
3.EntryId:資源類型對應的具體資源的Id
舉個栗子:0x7f020027。其中0x7f是包ID,02是資源類型id,0027是資源id
其實如果我們想要解決資源沖突的問題就把packageid改掉就行了,宿主肯定是0x7f默認的,那我們把插件的改為0x71、0x72、0x73這種數值就行了,你們怎么辦?
一種比較好用的辦法是在aapt的源代碼進行更改,在其把資源打包成0x7f之前,強制把0x7f改成我們傳遞過去的值。不過這種方式使用起來較為麻煩,需要修改並編譯aapt的源代碼,然后替換sdk目錄下的那個aapt。
aapt是c++寫的,所以我們只能找到c庫。
1.找到aapt的源代碼目錄aapt文件夾
2.找到ResourceTable.cpp並打開,搜索0x7f,是的就是在這個地方做更改的。
3.新建一個gradle插件,把需要傳遞的值通過gradle傳遞過去。例如;0x71、0x72等。