Android构建过程——资源合并打包

Android构建会经历资源合并打包、源码编译、dex生成及打包签名等步骤。
本文对资源合并打包进行一下小的总结

资源合并

《Android构建过程——资源合并打包》 资源合并.png

上面一图总结了在构建过程中的资源合并情况。

  1. 资源合并包括本地与第三方库的assets目录res目录Androidmanifest.xml
  2. 对于assets目录res目录res/values文件夹除外)的资源合并一旦发生冲突,会优先使用本地资源。
  3. 对于res/values文件夹,会进行内容上的合并,后合并的会覆盖有冲突的前面资源,而且合并先后顺序无法确定。
  4. 对于Androidmanifest.xml,我们的apk最终只会包含一个AndroidManifest.xml,但是因为我们的main source setbuild variants和引入的第三方依赖都可能存在Manifest文件,这时候就需要做合并。如果一个低优先级的xml结点不能匹配任何高优先级的结点就会被加入到高优先级的Manifest文件里,如果匹配上了则会进行合并,如果该结点下的存在相同属性在不同文件里具有不同的值时则会报错需要在较高优先级的manifest文件里添加合并规则标识。(Androidmanifest.xml的优先级:buildType 设置 > productFlavor 设置 > src/main > dependency&library
  5. 合并规则标识
  • merge:默认合并操作。
  • remove:移除指定的低优先级的属性
  • remove-All:移除相同节点类型下所有低优先级的属性
  • replace:高优先级替换低优先级Manifest文件中的属性
  1. 另外,manifest在对文件进行合并后,还会根据build.gradle的设置覆盖相关属性。

举个例子,下面代码进行合并,最后的 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"
        <!-- 合并规则标识 -->
        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 相当于占位符的意思,会替换覆盖Manifest文件对应的属性-->
            manifestPlaceholders = [ activityLabel:"freeName"]
        }
        pro {
            manifestPlaceholders = [ activityLabel:"proName" ]
        }
   }
}

<!--Manifest文件-->
<activity android:name=".MainActivity" android:label="${activityLabel}" >

AAPT打包

通过AAPTAndroid Asset Packaging Tool)处理后,会输出2个文件:

  • 一个为为app.ap,实际上为一个压缩包,包含了assetsresAndroidmanifest.xmlresources.arsc
  • 一个R.java,为项目各资源分配了不同的id,id为4字节无符号(8位)整数,最高字节表示package id,次高字节表示type id,后2字节表示资源在当前类型中出现的序号,如R.string.appname=0x7f07006b中的0x7f代表当前正在编译的资源包,0x07代表string类型,0x006b代表app_name在string类型中出现的序号。(这里package id为插件化的资源合并提供了可操作的地方)

assets是不需要做任何处理的,res/raw只需分配id后与assets一起直接打包到应用程序中;基于下述原因,其它xml文件则会被编译成二进制。

  • 编译过程中,会把xml中的所有的字符串进行收集去重,形成字符串资源池,元素中用到字符串的地方将被替换成相应的索引,进一步减少文件大小。(字符串变成了整数值的索引,相同字符串引用同一个索引)
  • 二进制格式的xml把标签属性/値转换为相应的索引后,避免了字符串解析,从而提高了解析速度。

《Android构建过程——资源合并打包》 字符串被替换成相应的索引

资源索引表resources.arsc记录了从资源id到文件路径的转换关系,当应用通过Resources类获取res文件资源时,会先从resources.arsc中拿到文件路径,然后通过AssetManager进行访问。

  • Android资源管理框架实际就是由AssetManager和Resources两个类来实现的。
  • Resources类可以根据ID来查找资源。
  • AssetManager类根据文件名来查找资源。

《Android构建过程——资源合并打包》 资源寻找过程
《Android构建过程——资源合并打包》 resources.arsc

再补上一张官方图总结总结应用程序资源的编译、打包以及查找过程

《Android构建过程——资源合并打包》 Paste_Image.png

参考文章:

  1. Android构建过程分析
  2. Android应用程序资源的查找过程分析
  3. Android应用程序资源的编译和打包过程分析
    原文作者:SamanLan
    原文地址: https://www.jianshu.com/p/ccf7184b5547
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞