Android構(gòu)建會經(jīng)歷資源合并打包少漆、源碼編譯僧诚、dex生成及打包簽名等步驟扯俱。
本文對資源合并打包進(jìn)行一下小的總結(jié)
資源合并
資源合并.png
上面一圖總結(jié)了在構(gòu)建過程中的資源合并情況脖律。
- 資源合并包括本地與第三方庫的
assets目錄
些膨、res目錄
蟀俊、Androidmanifest.xml
- 對于
assets目錄
、res目錄
(res/values文件夾除外
)的資源合并一旦發(fā)生沖突订雾,會優(yōu)先使用本地資源肢预。 - 對于
res/values文件夾
,會進(jìn)行內(nèi)容上的合并洼哎,后合并的會覆蓋有沖突的前面資源烫映,而且合并先后順序無法確定。 - 對于
Androidmanifest.xml
噩峦,我們的apk最終只會包含一個AndroidManifest.xml
锭沟,但是因為我們的main source set
,build variants
和引入的第三方依賴都可能存在Manifest
文件识补,這時候就需要做合并族淮。如果一個低優(yōu)先級的xml結(jié)點(diǎn)不能匹配任何高優(yōu)先級的結(jié)點(diǎn)就會被加入到高優(yōu)先級的Manifest文件里,如果匹配上了則會進(jìn)行合并,如果該結(jié)點(diǎn)下的存在相同屬性在不同文件里具有不同的值時則會報錯需要在較高優(yōu)先級的manifest文件里添加合并規(guī)則標(biāo)識瞧筛。(Androidmanifest.xml的優(yōu)先級:buildType
設(shè)置 >productFlavor
設(shè)置 >src/main
>dependency&library
) - 合并規(guī)則標(biāo)識
- merge:默認(rèn)合并操作厉熟。
- remove:移除指定的低優(yōu)先級的屬性
- remove-All:移除相同節(jié)點(diǎn)類型下所有低優(yōu)先級的屬性
- replace:高優(yōu)先級替換低優(yōu)先級
Manifest
文件中的屬性
- 另外,manifest在對文件進(jìn)行合并后较幌,還會根據(jù)build.gradle的設(shè)置覆蓋相關(guān)屬性揍瑟。
舉個例子,下面代碼進(jìn)行合并乍炉,最后的 label 是 app_name绢片;allowBackup 是 true。
<!--src/main的Androidmanifest.xml-->
<application
android:name="MyApplication"
android:icon="@drawable/ic_launcher"
android:allowBackup="true"
android:label="@string/app_name"
<!-- 合并規(guī)則標(biāo)識 -->
tools:replace="android:allowBackup,android:label">
</application>
<!--dependency&library的Androidmanifest.xml-->
<application
android:name="MyApplication"
android:icon="@drawable/ic_launcher"
android:allowBackup="false"
android:label="@string/app_name222">
</application>
下面代碼向Manifest文件注入build變量值
<!--Gradle文件-->
android {
productFlavors {
free {
<!--manifestPlaceholders 相當(dāng)于占位符的意思岛琼,會替換覆蓋Manifest文件對應(yīng)的屬性-->
manifestPlaceholders = [ activityLabel:"freeName"]
}
pro {
manifestPlaceholders = [ activityLabel:"proName" ]
}
}
}
<!--Manifest文件-->
<activity android:name=".MainActivity" android:label="${activityLabel}" >
AAPT打包
通過AAPT
(Android Asset Packaging Tool
)處理后底循,會輸出2個文件:
- 一個為為app.ap,實(shí)際上為一個壓縮包槐瑞,包含了
assets
熙涤、res
、Androidmanifest.xml
與resources.arsc
困檩。 - 一個
R.java
祠挫,為項目各資源分配了不同的id,id為4字節(jié)無符號(8位)整數(shù)悼沿,最高字節(jié)表示package id
等舔,次高字節(jié)表示type id
,后2字節(jié)表示資源在當(dāng)前類型中出現(xiàn)的序號糟趾,如R.string.appname=0x7f07006b中的0x7f代表當(dāng)前正在編譯的資源包慌植,0x07代表string類型,0x006b代表app_name在string類型中出現(xiàn)的序號义郑。(這里package id為插件化的資源合并提供了可操作的地方)
assets是不需要做任何處理的蝶柿,res/raw只需分配id后與assets一起直接打包到應(yīng)用程序中;基于下述原因魔慷,其它xml文件則會被編譯成二進(jìn)制只锭。
- 編譯過程中,會把xml中的所有的字符串進(jìn)行收集去重院尔,形成字符串資源池,元素中用到字符串的地方將被替換成相應(yīng)的索引喉誊,進(jìn)一步減少文件大小邀摆。(字符串變成了整數(shù)值的索引,相同字符串引用同一個索引)
- 二進(jìn)制格式的xml把標(biāo)簽屬性/値轉(zhuǎn)換為相應(yīng)的索引后伍茄,避免了字符串解析栋盹,從而提高了解析速度。
字符串被替換成相應(yīng)的索引
資源索引表resources.arsc
記錄了從資源id到文件路徑的轉(zhuǎn)換關(guān)系敷矫,當(dāng)應(yīng)用通過Resources
類獲取res
文件資源時例获,會先從resources.arsc
中拿到文件路徑汉额,然后通過AssetManager
進(jìn)行訪問。
- Android資源管理框架實(shí)際就是由AssetManager和Resources兩個類來實(shí)現(xiàn)的榨汤。
- Resources類可以根據(jù)ID來查找資源蠕搜。
- AssetManager類根據(jù)文件名來查找資源。
資源尋找過程
resources.arsc
再補(bǔ)上一張官方圖總結(jié)總結(jié)應(yīng)用程序資源的編譯收壕、打包以及查找過程
Paste_Image.png
參考文章: