我們平時(shí)在android studio中點(diǎn)擊run 衣屏,就能把代碼編譯成一個(gè)apk文件并安裝到手機(jī)上后添。那么這個(gè)過(guò)程中都具體發(fā)生了什么 ?我們是怎么把代碼和資源文件打包成一個(gè)apk文件,并安裝到手機(jī)上的呢 颇蜡? 今天就詳細(xì)研究一下這個(gè)流程 。
Apk構(gòu)建基本流程
上圖是Android官方提供的打包簡(jiǎn)略流程圖。清晰地展示了一個(gè)Android Project經(jīng)過(guò)編譯和打包后生成apk文件风秤,然后再經(jīng)過(guò)簽名鳖目,就可以安裝到設(shè)備上
我們將一個(gè)實(shí)際的apk文件后綴改為zip并解壓后,得到的內(nèi)容如下
和上圖的描述一致缤弦。apk包內(nèi)容包括:
- classes.dex…
- resources.arsc
- assets
- res
- AndroidManifest.xml
- META-INF
其中:
- res中圖片和raw文件下內(nèi)容保持原樣疑苔,res中其他xml文件內(nèi)容均轉(zhuǎn)化為二進(jìn)制形式;assets文件內(nèi)容保持原樣
- res中的文件會(huì)被映射到R.java文件中甸鸟,訪問(wèn)的時(shí)候直接使用資源ID即R.id.filename惦费;assets文件夾下的文件不會(huì)被映射到R.java中,訪問(wèn)的時(shí)候需要AssetManager類
在看下這張圖 抢韭,android apk構(gòu)建詳細(xì)流程圖
打包步驟:
1. 通過(guò)aapt打包res資源文件薪贫,生成R.java、resources.arsc和res文件(二進(jìn)制 & 非二進(jìn)制如res/raw和pic保持原樣) 刻恭,詳細(xì)步驟如下
檢查AndroidManifest.xml瞧省,主要做一些檢查并使用parsePackage初始化并設(shè)置一些attribute,比如package, minSdkVersion, uses-sdk鳍贾。
添加被引用資源包使用table.addIncludedResources(bundle, assets)添加被引用資源包鞍匾,比如系統(tǒng)的那些android:命名空間下的資源。
收集資源文件,處理overlay(重疊包骑科,如果指定的重疊包有和當(dāng)前編譯包重名的資源橡淑,則使用重疊包的):
將收集到的資源文件加到資源表(ResourceTable)對(duì)res目錄下的各個(gè)資源子目錄進(jìn)行處理,函數(shù)為makeFileResources:makeFileResources會(huì)對(duì)資源文件名做合法性檢查咆爽,并將其添加到ResourceTable內(nèi)梁棠。
編譯values資源并添加到資源表,在上一步添加過(guò)程中,其實(shí)并沒(méi)有對(duì)values資源進(jìn)行處理斗埂,因?yàn)関alues比較特殊符糊,需要經(jīng)過(guò)編譯之后,才能添加到資源表中呛凶。
給bag資源分配id,在繼續(xù)編譯其他資源之前男娄,我們需要先給bag資源(attrs,比如orientation這種屬性的取值范圍定義的子元素)分配id漾稀,因?yàn)槠渌Y源可能對(duì)它們有引用模闲。
編譯xml資源文件,最后我們終于可以編譯xml文件了,因?yàn)槲覀円呀?jīng)為它準(zhǔn)備好了一切可能引用到的東西(value, drawable等)县好。程序會(huì)對(duì)layouts, anims, animators等逐一調(diào)用
ResourceTable.cpp的,進(jìn)行編譯围橡,內(nèi)部流程又可以分為:解析xml文件,賦予屬性名稱資源id缕贡,解析屬性值翁授,扁平化為二進(jìn)制文件拣播。
編譯AndroidManifest.xml文,拿到AndroidManifest.xml文件,清空原來(lái)的數(shù)據(jù),重新解,處理package name重載收擦,把各種相對(duì)路徑的名字改為絕對(duì)路徑,編譯manifest xml文件,生成最終資源表.9.生成R.java文件
生成我們解壓后看到的那個(gè)resources.arsc:
2. 處理.aidl文件贮配,生成對(duì)應(yīng)的Java接口文件
- aidl,全名Android Interface Definition Language塞赂,即Android接口定義語(yǔ)言泪勒。
輸入:aidl后綴的文件。輸出:可用于進(jìn)程通信的C/S端java代碼宴猾,位于build/generated/source/aidl圆存。
3. 通過(guò)Java Compiler編譯R.java、Java接口文件仇哆、Java源文件沦辙,生成.class文件
我們有了R.java和aidl生成的Java文件,再加上工程的源代碼讹剔,現(xiàn)在可以使用javac進(jìn)行正常的java編譯生成class文件了油讯。
輸入:java source的文件夾(另外還包括了build/generated下的:R.java, aidl生成的java文件,以及BuildConfig.java)延欠。輸出:對(duì)于gradle編譯陌兑,可以在build/intermediates/classes里,看到輸出的class文件由捎。
源碼編譯之后兔综,我們可能還會(huì)對(duì)其進(jìn)行代碼的混淆,混淆的作用是增加反編譯的難度隅俘,同時(shí)也將一些代碼的命名進(jìn)行了縮短邻奠,減少代碼占用的空間∥樱混淆完成之后,會(huì)生成一個(gè)混淆前后的映射表杀狡,這個(gè)是用來(lái)在反應(yīng)我們的應(yīng)用執(zhí)行的時(shí)候的一些堆棧信息蒙畴,可以將混淆后的信息轉(zhuǎn)化為我們混淆前實(shí)際代碼中的內(nèi)容。
4. 通過(guò)dex命令呜象,將.class文件和第三方庫(kù)中的.class文件處理生成classes.dex
調(diào)用dx.bat將所有的class文件(上一步生成的以及第三方庫(kù)的)轉(zhuǎn)化為classes.dex文件膳凝,dx會(huì)將class轉(zhuǎn)換為Dalvik字節(jié)碼,生成常量池恭陡,消除冗余數(shù)據(jù)等蹬音。
5. 通過(guò)apkbuilder工具,將aapt生成的resources.arsc和res文件休玩、assets文件和classes.dex一起打包生成apk
打包生成APK文件著淆。舊的apkbuilder腳本已經(jīng)廢棄劫狠,現(xiàn)在都已經(jīng)通過(guò)sdklib.jar的ApkBuilder類進(jìn)行打包了。輸入為我們之前生成的包含resources.arcs的.ap_文件永部,上一步生成的dex文件独泞,以及其他資源如jni、jar包內(nèi)的資源苔埋。
大致步驟為
以包含resources.arcs的.ap_文件為基礎(chǔ)懦砂,new一個(gè)ApkBuilder,設(shè)置debugMode
apkBuilder.addZipFile(f);
apkBuilder.addSourceFolder(f);
apkBuilder.addResourcesFromJar(f);
apkBuilder.addNativeLibraries(nativeFileList);
apkBuilder.sealApk(); // 關(guān)閉apk文件
generateDependencyFile(depFile, inputPaths, outputFile.getAbsolutePath());
6. 通過(guò)Jarsigner工具组橄,對(duì)上面的apk進(jìn)行debug或release簽名
對(duì)apk文件進(jìn)行簽名荞膘。APK需要簽名才能在設(shè)備上進(jìn)行安裝很多時(shí)候我們?cè)谀嫦蚋耐旰螅瑫?huì)因?yàn)闆](méi)有簽名文件導(dǎo)致最后的apk無(wú)法正常使用玉工,又細(xì)分為本地驗(yàn)證和服務(wù)器驗(yàn)證衫画。
7. 通過(guò)zipalign工具,將簽名后的apk進(jìn)行對(duì)齊處理瓮栗。
調(diào)用buildtoolszipalign削罩,對(duì)簽名后的apk文件進(jìn)行對(duì)齊處理欣舵,使apk中所有資源文件距離文件起始偏移為4字節(jié)的整數(shù)倍荆永,從而在通過(guò)內(nèi)存映射訪問(wèn)apk文件時(shí)會(huì)更快。同時(shí)也減少了在設(shè)備上運(yùn)行時(shí)的內(nèi)存消耗释牺。這樣我們的最終apk就生成完畢了愿阐。
關(guān)于zipalign工具微服,根據(jù)名字就知道是個(gè)zip文件對(duì)齊的工具。使得apk中的資源文件偏離文件起始位置4個(gè)字節(jié)缨历,從而可以通過(guò)mmap()直接訪問(wèn)以蕴,從而減少RAM占用。
參考文檔
1辛孵、官網(wǎng) :配置構(gòu)建
2丛肮、apk 構(gòu)建流程
3、Android打包系列——打包流程梳理
4魄缚、APK打包安裝過(guò)程