笔记大量参考老罗的资源编译打包系列文章.

一、资源分类
Android应用程序资源可以分为两大类, 分别是assets和res;
1.1 assets目录
assets目录下的文件最终会被原封不动地打包在apk文件中, 如果要在程序中访问这些文件, 那么就需要指定文件名来访问这些文件, 那么就需要指定文件名来访问.
1.2 res目录
res目录下的文件大多都会被编译, 并且都会被赋予资源ID. res类资源按照不同的用途可以进一步划分为以下9种子类型:
1、animator: 这类资源以XML文件保存在res/animator目录下, 用来描述属性动画.
2、anim: 这类资源以XML文件保存在res/anim目录下, 用来描述补间动画.
3、color:
4、drawable:
5、layout:
6、menu:
7、raw: 这类资源以任意格式的文件保存在res/raw目录下, 它们和assets类资源一样, 都是原封不动地打包在apk文件中, 不过它们会被赋予资源ID, 然后在程序中通过ID来访问它们.
8、values:
9、xml: 这类资源以XML文件保存在res/xml目录下, 一般就是用来描述应用程序的配置信息.
1.3 xml编译打包
1、上面9种类型资源文件除了raw类型资源, 以及Bitmap文件的drawable类型资源之外, 其它的资源文件均为文本格式的XML文件, 它们在打包过程中, 会被编译成二进制格式的XML文件. 这些二进制格式的XML文件分别有一个字符串资源池, 用来保存文件中引用到的每一个字符串, 包括XML元素标签、属性名称、属性值, 以及其它的一切文本值所使用到的字符串. 这样原来在文本格式的XML文件中的每一个放置字符串的地方在二进制格式的XML文件中都被替换成一个索引到字符串资源池的整数值. 这样做有两个好处:
(1)文件占用更小: 例如, 假设在原来的文本格式的XML文件中, 有四个地方使用的都是同一个字符串, 那么在最终编译出来的二进制格式的XML文件中, 字符串资源池只有一份字符串值, 而引用它的四个地方只占用一个整数值.
(2)解析速度更快: 由于在二进制格式的XML文件中, 所有的XML元素标签和属性等值都是使用整数来描述的, 因此在解析的过程中, 就不再需要进行字符串解析, 这样就可以提高解析速度.
2、每一个res资源在编译打包完成之后, 都会被分配一个资源ID, 这些资源ID最终会被定义为java常量值, 保存在一个R.java文件中, 与应用程序的其他源文件一起被编译到程序中, 这样我们就可以在程序或者资源文件中通过这些ID常量来访问指定的资源.
二、资源编译打包
Android资源打包工具aapt在编译和打包资源的过程中, 会执行以下两个额外的操作:
1、赋予每一个非assets资源一个ID值, 这些ID值以常量的形式定义在一个R.java文件中.
2、生成一个resources.arsc文件, 用来描述那些具有ID值得资源的配置信息, 它的内容相当于是一个资源索引表.
2.1 资源表
Android资源打包工具在编译应用程序资源之前, 会创建一个资源表. 这个资源表使用一个ResourceTable对象来描述, 当应用程序资源编译完成之后, 它就会包含所有资源的信息. 有了这个资源索引表之后, Android资源打包工具就可以根据它的内容来生成资源索引表文件resources.arsc了.
2.2 应用程序资源的编译和打包过程
1、解析AndroidManifest.xml;
2、添加被引用资源包;
3、收集资源文件;
4、将收集到的资源增加到资源表;
5、编译values类资源;
6、给Bag资源分配ID;
7、编译Xml资源文件;
8、生成资源符号;
9、生成资源索引表;
10、编译AndroidManifest.xml文件;
11、生成R.java文件;
12、打包APK文件;
2.2.1 解析AndroidManifest.xml
解析AndroidManifest.xml是为了获得要编译资源的应用程序的包名称. 在AndroidManifest.xml文件中, manifest标签的package属性的值描述的就是应用程序的包名称, 有了这个包名称之后, 就可以创建资源表了, 即创建一个ResourceTable对象.
2.2.2 添加被引用资源包
编译一个Android应用程序的资源的时候, 至少会涉及到两个包, 其中一个是被引用的系统资源包, 另外一个就是当前正在编译的应用程序资源包. 每一个包都可以定义自己的资源, 同时它也可以引用其它包的资源. 包通过资源ID来引用其它包的资源的, 这个资源ID是一个4字节的无符号整数, 其中最高字节表示Package ID, 次高字节表示Type ID, 最低两字节表示Entry ID.
Package ID相当于是一个命名空间, 限定资源的来源. Android系统当前定义了两个资源命名空间, 其中一个是系统资源命名空间, 他的Package ID是0x01, 另外一个是应用程序资源命名空间, 它的Package ID等于0x7f. 所有位于[0x01, 0x7f]之间的Package ID都是合法的, 在这个范围之外的都是非法的Package ID.
2.2.3 收集资源文件
在编译应用程序资源之前, Android资源打包工具aapt会创建一个AaptAssets对象, 用来收集当前需要编译的资源文件.
2.2.4 将收集到的资源增加到资源表
前面收集到的资源只是保存在一个AaptAssets对象中, 这一步需要将这些资源同时增加到一个资源表中, 即增加到前面所创建的一个ResourceTable对象中去, 因为最后我们需要根据这个ResourceTable来生成资源索引表, 即生成resources.arsc文件.
2.7 编译Xml资源文件
编译Xml资源文件又细分为以下几个步骤:
1、解析Xml文件;
2、赋予属性名称资源ID;
3、解析属性值;
4、压平Xml文件;
针对压平Xml文件又包括以下以下几步:
1、收集有资源ID的属性的名称字符串;
2、收集其他字符串;
3、写入Xml文件头;
4、写入字符串资源池;
5、写入资源ID;
6、压平Xml文件;
2.7.1 解析Xml文件
解析Xml文件是为了可以在内存中用一系列树形结构的XMLNode来表示XML文件.
2.7.2 赋予属性名称资源ID
这一步实际上是给每一个Xml元素的属性名称赋予资源ID. 每一个Xml文件都是从根节点开始给属性名称赋予资源ID, 然后再递归给每一个子节点的属性名称赋予资源ID, 直到每一个节点的属性名称都获得了资源ID为止. 例如对<LinearLayout android:orientation="vertical"/>中的android:orientation进行赋值.
2.7.3 解析属性值
对Xml元素的属性的值进行解析, 例如对<LinearLayout android:orientation="vertical"/>中的vertical进行赋值.
2.7.4 压平Xml文件
经过
解析Xml文件、赋予属性名称资源ID、解析属性值
这三步操作之后, 所需要的基本材料都已经准备好了, 接下来就可以对Xml文件的内容进行扁平化处理了, 实际上就是将Xml文件从文本格式转换为二进制格式.
2.7.4.1 收集有资源ID的属性的名称字符串
除了收集那些具有资源ID的Xml元素属性的名称字符串之外, 还会将对应的资源ID收集起来放在一个数组中, 这里收集到的属性名称字符串保存在一个字符串资源池中, 它们与收集到的资源ID数组是一一对应的.

2.7.4.2 收集其它字符串
这一步收集的是Xml文件中的其他所有字符串. 对于收集过的不会再重复收集.
2.7.4.3 写入Xml文件头
最终编译出来的Xml二进制文件是一系列的chunk组成的, 每个chunk都有一个头部, 用来描述chunk的元信息.
2.7.4.4 写入字符串资源池
收集完字符串以后, 将他们写入到最终收集到二进制格式的Xml文件中.
2.7.4.5 写入资源ID
收集起来的资源ID会作为一个单独的chunk写入到最终的二进制Xml文件中去, 这个chunk位于字符串资源池的后面.
2.7.4.6 压平Xml文件
压平Xml文件其实就是将里面的各个Xml元素中的字符串都替换掉, 这些字符串要么是被替换到字符串资源池的一个索引, 要么是替换成一个具有类型的其他值.
2.8 生成资源符号
这里生成资源符号为后面生成R.java文件做好准备的, 从前面的操作可以知道, 所有收集到的资源项都按照类型来保存在一个资源表中, 即保存在一个ResourceTable对象中.
2.9 生成资源索引表

有了这些资源项之后, Android资源打包工具aapt就可以按照下面的流程来生成资源索引表resources.arsc文件了.
2.10 编译AndroidManifest.xml文件
2.11 生成R.java文件
在前面的第八步中, 我们已经将所有的资源项及其所对应的资源ID都收集起来了, 因此这里只要直接将它们写入到指定的R.java文件去就可以了. 例如, 假设分配给类型为layout的资源项main和sub的ID为0x7f030000和0x7f030001, 那么在R.java文件, 就会分别有两个以main和sub为名称的常量:
public final class R {
public static final class layout {
public static final int main = 0x7f030000;
public static final int sub = 0x7f030001;
}
}
2.12 打包APK文件
所有资源文件都编译以及生成完成之后, 就可以将它们打包到APK文件去了, 包括:
1、assets目录.
2、res目录, 但是不包括res/values目录, 这是因为res/values目录下的资源文件的内容经过编译过后, 都直接写入到资源项索引表去了.
3、资源项索引文件resources.arsc.
参考文章:
https://blog.csdn.net/luoshengyang/article/details/8738877
网友评论