前言
HI兰迫,歡迎來到《每周一博》信殊。今天是一月第一周,也是2019年的第一周汁果,今天我給大家介紹下APK的結(jié)構(gòu)涡拘。
APK其實就是個壓縮文件,我們把后綴改成ZIP之后解壓就可以看到里面的內(nèi)容主要有如下部分:
1.AndroidManifest.xml
該文件是每個應(yīng)用都必須包含的据德,它描述了應(yīng)用的名字鳄乏,版本,權(quán)限棘利,引用的庫文件等等信息橱野。APK中的AndroidManifest.xml是二進制文件,直接打開是亂碼善玫,需要反編譯水援。
2.META-INF目錄
META-INF目錄下存放的是簽名信息,用來保證apk包的完整性和系統(tǒng)的安全。打包時會對所有要打包的文件做一個校驗計算蜗元,并把計算結(jié)果放在META-INF目錄下或渤。這就保證了apk包里的文件不能被隨意替換。比如拿到一個apk包后奕扣,如果想要替換里面的一幅圖片薪鹦,一段代碼, 或一段版權(quán)信息惯豆,想直接解壓縮池磁,替換再重新打包,基本是不可能的楷兽。如此一來就給病毒感染和惡意修改增加了難度地熄,有助于保護系統(tǒng)的安全。
3.classes.dex文件
classes.dex是java源碼編譯后生成的java字節(jié)碼文件拄养。安卓的虛擬機解析的是dex文件而不是class离斩。dex文件中各個類能夠共享數(shù)據(jù),在一定程度上降低了冗余瘪匿,也使得文件結(jié)構(gòu)更加經(jīng)湊跛梗,節(jié)省體積。
4.resources.arsc
resources.arsc是編譯后的二進制資源文件棋弥,它是一個映射表核偿,映射著資源和id,通過R文件中的id就可以找到對應(yīng)的資源顽染。
5.res目錄
res目錄存放資源文件漾岳,包括圖片,字符串等等粉寞,像layout尼荆,drawable中的xml文件也都是經(jīng)過編譯的,直接打開是亂碼唧垦,需要使用apktools才能查看捅儒。
6.lib目錄
lib目錄下存放的是一些so文件,如果代碼中沒有so就沒有該目錄振亮。
7.assets目錄
assets目錄下是一些配置文件巧还,也可以是資源,這里的xml文件不會經(jīng)過編譯坊秸,如果代碼中沒有assets也不會有該目錄麸祷。
編譯APK主要有如下幾步:
- 根據(jù)資源文件和AndroidManifest.xml生成R.java文件
- 編譯AIDL,生成對應(yīng)的java文件褒搔,沒有則跳過
- 編譯工程源碼(主項目和庫)阶牍,同時上邊生成的R文件和AIDL生成的Java文件也會被編譯生成相應(yīng)的class文件
- 將class文件打包生成dex文件
- 將資源文件打包喷面,生成初始的apk
- 將生成的dex文件加入到apk中生成未簽名的包
- 對apk進行簽名
- 將簽名后的apk進行對齊處理,目的是減少程序運行時對內(nèi)存的占用
這里有幾個圖可以幫助理解下荸恕。
本文介紹了APK的基本結(jié)構(gòu)乖酬,下周會介紹APK的具體打包過程死相,感謝大家的閱讀融求,我們下周再見。
前言
HI算撮,歡迎來到《每周一博》生宛。今天是一月第二周,我給大家介紹下APK的打包過程肮柜。這篇文章是在上一篇《APK結(jié)構(gòu)介紹》的基礎(chǔ)上進行實踐陷舅,先上一張詳細的打包流程圖。
接下來我們用工具手動打包一個Android項目审洞。
1. 配置環(huán)境變量
我們用到的工具在build-tools目錄下的不同版本中莱睁。
AAPT_HOME=/Users/peizhifei/Library/Android/sdk/build-tools/27.0.3/
export AAPT_HOME
export PATH=$PATH:$AAPT_HOME
創(chuàng)建一個測試項目,然后拷貝/Users/peizhifei/Library/Android/sdk/platforms/android-27/android.jar到項目根目錄
2. 創(chuàng)建輔助目錄
進入項目下面芒澜,生成gen存放R文件仰剿,build放過程文件,out放輸出文件痴晦。
cd app/src/main/
mkdir -p app/src/main/{gen,build,out}
3. 生成R文件
要使用aapt工具南吮,輸入Manifest和res和android.jar來生成R文件。
aapt p -f -M ./app/src/main/AndroidManifest.xml
-I android.jar -S ./app/src/main/res/ -J ./app/src/main/gen/ -m
aapt命令參數(shù)含義:
-f : #如果編譯出來的文件已經(jīng)存在誊酌,強制覆蓋
-M : AndroidManifest.xml 的路徑
-I : android.jar的路徑
-S : 資源文件res 文件夾路徑
-J :生成 R.java 的輸出目錄
-m : 讓生成包的目錄放在 -J 參數(shù)指定的目錄
成功后可以再gen文件下會生成相應(yīng)的R.java文件部凑。
4. 編譯aidl文件
通過aidl工具就可以將aidl文件編譯成java文件。
aidl -Iapp/src app/src/main/aidl/com/example/peizhifei/myapplication/IMyAidlInterface.aidl
注意-Iapp/src之間是沒有空格的碧浊。
5. 編譯生成class文件
這一步就是用javac將項目中所有的java文件編譯成class文件涂邀。
javac -source 1.8 -target 1.8 -encoding UTF-8
-bootclasspath android.jar -d app/src/main/build/
app/src/main/java/com/example/peizhifei/myapplication/*.java
app/src/main/gen/com/example/peizhifei/myapplication/*.java
app/src/main/aidl/com/example/peizhifei/myapplication/*.java
命令參數(shù)含義如下:
-encoding :編碼方式,這里設(shè)置UTF-8箱锐;
-bootclasspath :引導(dǎo)類文件的路徑比勉,這里需要使用到android.jar中的Android API;
-d :生成的class文件存放路徑瑞躺;
這里指定了所有的java文件敷搪,包括源碼的,aidl編譯的java文件幢哨,gen里面的R文件赡勘,結(jié)果存在在build下面。
6. 將class文件生成dex文件
dex文件是Android虛擬機可運行文件捞镰,可以使用dx工具生成闸与。
dx --dex --output=app/src/main/build/classes.dex app/src/main/build/
輸入是所有的class文件毙替,輸出在build下面,如果方法數(shù)超過Integer.Max多會出現(xiàn)多個dex文件践樱。
7. 生成資源映射表
資源索引表resources記錄了從資源id到文件路徑的轉(zhuǎn)換關(guān)系厂画,當(dāng)應(yīng)用通過R文件使用資源時,會先從resources中拿到文件路徑拷邢,然后通過AssetManager進行訪問袱院。
aapt package -f -M app/src/main/AndroidManifest.xml
-I android.jar -S app/src/main/res/ -A app/src/main/assets
-F app/src/main/out/resources
這里依然用到了aapt工具,如果有assets文件需要加進來瞭稼。成功后會在out目錄下看到resources文件忽洛。
8. 生成資源APK和編譯后的xml文件
這一步要編譯xml文件為二進制文件,同時生成資源APK环肘。
aapt package -f -M app/src/main/AndroidManifest.xml
-I android.jar -S app/src/main/res/ -A app/src/main/assets
-F app/src/main/out/res.apk
這里只是輸出結(jié)果變成了APK欲虚,成功的話在out目錄下會看到res.apk。
9. 把代碼打入到APK里
上一步已經(jīng)生成了資源APK悔雹,但沒有代碼复哆,這一步我們把dex文件和resources打入到APK中。早期是直接使用apkbuilder工具直接打包腌零,但是目前sdk將該工具移除了梯找。其實apkbuilder最終調(diào)用的是sdklib.jar中的com.android.sdklib.build.ApkBuilderMain類來做事情的,所以這里直接通過 java <class地址> 使用ApkBuilderMain這個類莱没,把resources和classes.dex加入到apk文件中初肉。
java -classpath /Users/peizhifei/Library/Android/sdk/tools/lib/sdklib.jar
com.android.sdklib.build.ApkBuilderMain
app/src/main/out/res.apk -v -u -z
app/src/main/out/resources -f
app/src/main/build/classes.dex
成功的話可以打開res.apk,看到dex文件已經(jīng)打進去了饰躲。
10. 簽名APK
apk安裝必須要簽名牙咏,我們使用jarsigner給apk手動簽名,為了方便可以使用debug簽名嘹裂。
jarsigner -verbose -keystore ~/.android/debug.keystore
-storepass android -keypass android
app/src/main/out/res.apk androiddebugkey
jarsigner的命令格式是這樣的妄壶;
jarsigner -verbose -keystore <簽名.keystore> -signedjar <簽名ed.apk> <未簽名.apk> <別名>
11. 對齊優(yōu)化
至此APK就已經(jīng)生成了,可以安裝在手機上了寄狼,但是正常項目還是需要進行對齊優(yōu)化的丁寄,能加快apk解壓速度,需要用到zipalign工具泊愧。
zipalign -f 4 app/src/main/out/res.apk app/src/main/out/res_ zipalign.apk
成功后對齊的apk就是out目錄下res_ zipalign.apk伊磺。
12. 安裝并啟動
這里可以安裝APK到手機并啟動主界面
adb install -r app/src/main/out/res2.apk
adb shell am start -n
com.example.peizhifei.myapplication/.MainActivity
這里用了強制安裝,這樣就能覆蓋安裝删咱。
到此我們就大概實現(xiàn)了apk的打包過程屑埋,當(dāng)然在實際項目中,要比上邊的流程更復(fù)雜寫痰滋,包括多module依賴摘能,so文件引用续崖,代碼混淆等。
最后把所有這些命令都可以統(tǒng)一放到一個shell腳本里去執(zhí)行团搞。
為了路徑簡短严望,我把android.jar放到了app/src/main/下面,并進入到該目錄逻恐,避免每次輸入app/src/main/像吻。
#進入項目目錄
cd app/src/main/
#創(chuàng)建輔助目錄
mkdir -p {gen,build,out}
#生成R文件
aapt p -f -M AndroidManifest.xml -I android.jar -S res -J gen -m
#編譯aidl文件
aidl -Iapp/src aidl/com/example/peizhifei/myapplication/IMyAidlInterface.aidl
#編譯得到class文件
javac -source 1.8 -target 1.8 -encoding UTF-8 -bootclasspath android.jar -d build java/com/example/peizhifei/myapplication/*.java gen/com/example/peizhifei/myapplication/*.java aidl/com/example/peizhifei/myapplication/*.java
#缺一步混淆
#將class文件生成dex文件
dx --dex --output=build/classes.dex build/
#生成資源映射表
aapt package -f -M AndroidManifest.xml -I android.jar -S res -A assets -F out/resources
#生成資源和二進制文件
aapt package -f -M AndroidManifest.xml -I android.jar -S res -A assets -F out/res.apk
#把代碼打入到資源里
java -classpath /Users/peizhifei/Library/Android/sdk/tools/lib/sdklib.jar com.android.sdklib.build.ApkBuilderMain out/res.apk -v -u -z out/resources -f build/classes.dex
#簽名APK
jarsigner -verbose -keystore ~/.android/debug.keystore -storepass android -keypass android out/res.apk androiddebugkey
#對齊優(yōu)化
zipalign -f 4 out/res.apk out/res_zipalign.apk
#強制安裝
adb install -r out/res_zipalign.apk
#啟動主界面
adb shell am start -n com.example.peizhifei.myapplication/.MainActivity
直接執(zhí)行該腳本,手機上就會啟動主界面梢莽,簡單總結(jié)一下萧豆。
aapt是一個重要的工具奸披,來生成R.java文件和resource.arsc昏名。assets是不需要做任何處理的,res/raw只需分配id后與assets一起直接打包到應(yīng)用程序中阵面,其它xml文件則會被編譯成二進制文件轻局。編譯過程中,會把xml中的字符串進行收集去重样刷,形成字符串資源池仑扑,元素中用到字符串的地方將被替換成相應(yīng)的索引。另外標(biāo)簽屬性值都會轉(zhuǎn)換為資源id置鼻,進一步減少文件大小镇饮。二進制格式的xml把標(biāo)簽屬性值轉(zhuǎn)換為資源id后,避免了字符串解析箕母,從而提高了解析速度储藐。
另外就是生成資源APK后需要把代碼打入到APK里面,然后對APK做一些優(yōu)化處理即可嘶是。其實這個演示更多是為了加深對編譯過程的理解钙勃,比如插件化處理資源就會從aapt入手解決資源沖突,漢化可以考慮修改resource.arsc并進行二次打包等聂喇。
本文介紹了APK的打包過程辖源,實際操作演示了一下,感謝大家的閱讀希太,我們下周再見克饶。