国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

深入分析Android構建過程

2019-10-22 18:22:04
字體:
來源:轉載
供稿:網友

資源合并

如果項目引入了android support包,又或許依賴于其它第三方aar庫,那構建前會將aar解壓并與本地資源合并,這里的資源主要包括assets目錄,res目錄及Androidmanifest.xml。

當第三方依賴中的assets或res文件與本地文件有沖突時,會優先選用本地文件。但res/values略有不同,此目錄下的strings.xml、color.xml、styles.xml等文件會被整合到一個叫values.xml的文件中去,后與各第三方依賴中的values.xml進行內容上的合并,不會像res其它子目錄文件一樣直接舍棄第三方沖突文件。

Androidmanifest.xml的合并相比來說則要復雜一些,除了第三方依賴中的manifest,項目還可以在不同目錄下分別擁有manifest文件。構建過程中,會根據manifest中元素、屬性及賦值來生成一個manifest文件,并應用于后續的打包過程。gradle為不同的manifest賦予了不同的優先級,其順序如下:

buildType 設置 > productFlavor 設置 > src/main > dependency&library
XML元素及屬性的沖突會根據以下規則進行解決:

Android,構建過程

當然也會有一些例外的:

uses-feature android:required與uses-library android:required默認為true,根據or規則合并;

如未指定uses-sdk,minSdkVersion跟targetSdkVersion將被設置為1。而沖突時會使用高優化級的設置;

若library的minSdkVersion高于src/main的設置,則會引發error,但可通過overrideLibrary解決。若未指定targetSdkVersion,則其值與minSdkVersion一致;

若library的targetSdkVersion低于src/main的設置,需要添加一些額外的權限保證library能正常運行;

manifest元素只與子manifest元素合并;

intent-filter元素在合并中不會被改變,只會被添加到其父節點中去;

沖突發生時,可通過合并沖突標記進行解決,需要引入android tools命名空間,詳情請參閱官方文檔。另外,manifest在對文件進行合并后,還會根據build.gradle的設置覆蓋相關屬性。

AAPT打包

資源合并后,即進入到編譯階段,先會把項目資源中的xml編譯成二進制并生成R.java及資源索引表resources.arsc,其流程如下:

Android,構建過程

由圖可見,assets是不需要做任何處理的,res/raw只需分配id后與assets一起直接打包到應用程序中;基于下述原因,其它xml文件則會被編譯成二進制。

編譯過程中,會把xml中的字符串進行收集去重,形成字符串資源池,元素中用到字符串的地方將被替換成相應的索引。另外,標簽屬性/値都會轉換為資源id,進一步減少文件大小;

二進制格式的xml把標簽屬性/値轉換為資源id后,避免了字符串解析,從而提高了解析速度;

經過AAPT(Android Asset Packaging Tool)處理后,會輸出2個文件:一個R.java,為項目各資源分配了不同的id,將和java源碼一起參與到后續的編譯過程,id為4字節無符號整數,最高字節表示package id,次高字節表示type id,后2字節表示資源在當前類型中出現的序號,如R.string.appname=0x7f07006b中的0x7f代表當前正在編譯的資源包,0x07代表string類型,0x006b代表app_name在string類型中出現的序號;另一個為app.ap,實際上為一個壓縮包,包含了assets、res、Androidmanifest.xml與resources.arsc

資源索引表resources.arsc記錄了從資源id到文件路徑的轉換關系,當應用通過Resources類獲取res文件資源時,會先從resources.arsc中拿到文件路徑,然后通過AssetManager進行訪問。

Application Component -> resources.arsc -> AssetManager -> apk
從上述流程中可以看到,若要進行資源的混淆,可在分析resources.arsc格式后,修改內容中文件路徑的指向并對資源文件進行相應的重命名即可。

另外,AAPT還可對png圖進行優化、指定文件以stored還是deflated模式添加到壓縮包中等操作。

源碼編譯

當項目中包含aidl時,會先調用aidl工具生成java代碼;renderscript亦然,需要先調用llvm-rs-cc,只是它不僅會自動生成java文件,還會產生相應的.bc文件,.bc文件將打包到apk中

Android,構建過程

至此,java代碼都已準備完畢。下一步要進行的是通過javac命令將java源碼編譯成.class字節碼,用以編譯的classpath包含以下內容:

android.jar,具體版本由targetSdkVersion指定;

build.gradle中添加的第三方依賴;

編譯后可對代碼進行混淆處理,主要包括刪除無用類、字節碼優化、重命名等操作,只需在build.gradle中配置混淆規則即可

buildTypes {  release {    minifyEnabled true    proguardFiles getDefaultProguardFile('proguard-android.txt')    proguardFile 'proguard/proguard-rules.pro'  }}

生成dex

如果項目涉及分dex,那在調用dx命令前,需要做一些準備的工作,把編譯后的class文件打包成jar包allclasses.jar,然后生成主dex中必須包含的文件列表。主要包括collect、shrink及create 3個步驟。

Android,構建過程

首先會通過Androidmanifest.xml過濾出項目中使用到的四大組件(Activity、Service、receiver、provider)、Application及Instrumentation,并寫入manifest_keep.txt文件,這些都是會默認添加到主dex的,無須手動設置。除此之外,默認添加的還有繼承于 BackupAgent 及 Annotation 的類。若有額外的類需要被加入到主dex中,可以新建一個文件并以proguard的語法指定,然后在build.gradle中把此文件配置到multiDexKeepProguard中去。此過程關鍵代碼如下:

void generateKeepListFromManifest() {  SAXParser parser = SAXParserFactory.newInstance().newSAXParser()  Writer out = new BufferedWriter(new FileWriter(getOutputFile()))  try {    parser.parse(getManifest(), new ManifestHandler(out))    // add a couple of rules that cannot be easily parsed from the manifest.    out.write("""-keep public class * extends android.app.backup.BackupAgent {<init>();}-keep public class * extends java.lang.annotation.Annotation {*;}""")    if (proguardFile != null) {      out.write(Files.toString(proguardFile, Charsets.UTF_8))    }  } finally {    out.close()  }}

這個時候,會執行一個叫shrinkXxxMultiDexComponents(Xxx為build types名稱)的任務。實際上是調用了proguard,只是要比常規的proguard簡單一些,不執行混淆、優化跟預檢幾個步驟,只需要shrink即可,以allclasses.jar為輸入、manifest_keep.txt為混淆配置文件,把指定內容及其引用標記起來,然后添加到componentClasses.jar中去。

public void execute(ProGuardTask proguardComponentsTask) {  proguardComponentsTask.dontobfuscate();  proguardComponentsTask.dontoptimize();  proguardComponentsTask.dontpreverify();  // 方法未完,略過...}

到了CreateMainDexList,會調用dx命令,傳入allclasses.jar、componentClasses.jar,分析后者依賴,把它直接引用的類也添加到主dex中,并生成新的multidex配置文件maindexlist.txt,至此,準備工作完成。

經過上一階段編譯的處理,已經生成了標準的java字節碼,可在標準的java虛擬機上運行。但android使用了它特有的dalvik虛擬機,這就需要我們為它提供另一不同的格式。dx工具為此而出現,可將.classes文件轉換添加到dalvik可執行文件.dex中去。當項目發展到一定規模,需要進行分dex處理時,可通過上述步驟生成的maindexlist.txt指定dex該如何拆分。

遺憾的是,以上關于分dex的內容都是理想的情況,現實卻很殘酷。如果項目中開啟了proguard,那它會在分dex的shrink處理前完成,導致allclasses.jar是混淆處理后的代碼,而manifest_keep.txt卻未曾混淆,后續生成componentClasses.jar 及 maindexlist.txt 的過程也就都不再可靠了。要解決這個問題,在shrink前通過混淆輸出的符號表mapping.txt對manifest_keep.txt進行修正是個不錯的選擇。

打包簽名

此時萬事俱備,只要把資源包app.ap_、可執行文件classes.dex及項目(包含第三方依賴)中的非源碼文件一起添加到壓縮包中去,我們的安裝包(.apk文件)也就生成了。

另外,apk需要經過簽名才可以發布。可通過jarsigner工具完成。

zipalign

文件對齊并非android構建的必要步驟,但對齊處理后可提高系統訪問安裝包資源的效率。即使執行了zipalign,也只有以stored模式添加到apk中的文件是需要對齊的。如若對圖片等資源進行了極限壓縮或在aapt打包時選擇了deflated,那可對齊的文件也就沒多少了

通過build tools中的zipalign工具以下命令可對壓縮包進行對齊

zipalign -f -v 4 app.apk toapp.apk
以下命令則起到了檢驗壓縮包有沒有對齊的作用:

zipalign -c -v 4 app.apk
總結

本文主要介紹了android構建的各個主要步驟,并重點講述了資源合并打包與dex生成的過程。最后,用一張圖概括下構建的總體流程:

Android,構建過程

 

注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 惠东县| 镇江市| 游戏| 南通市| 平利县| 奉贤区| 靖安县| 大名县| 喀喇沁旗| 通城县| 扶余县| 巨鹿县| 台北市| 永福县| 宁河县| 雷州市| 社会| 井冈山市| 伊宁市| 卢龙县| 平湖市| 天峻县| 寿阳县| 行唐县| 砚山县| 洱源县| 嘉禾县| 连州市| 繁峙县| 北流市| 建宁县| 潼关县| 越西县| 耒阳市| 乌兰浩特市| 广饶县| 开封市| 虞城县| 宝山区| 扶沟县| 阳新县|