本文已参加好文征集活动,点击查看:【后端大前端双轨提交,2万元奖池等你挑战! ]
前言
在工作和学习中,我们除了编写一些业务代码外,还需要对项目的编译和打包流程有一定的了解,这样在遇到相关问题时才能有头绪。 在这个过程中,我们经常会忽略资源文件是如何添加的。 资源管理框架是一个非常庞大和复杂的框架。 资源编译和打包的过程也非常复杂和繁琐。 本文就简单说一下。 资源文件是如何编译打包的? 除了自我总结之外,希望能够对阅读本文的你有所帮助和启发。 当然,文章比较长,希望大家能够耐心阅读。
编译打包过程
一个包中除了代码之外,还有很多资源文件。 这些资源文件在apk打包过程中通过AAPT工具打包到apk中。 我们先看一下apk的打包流程图。
总结一下这张图,打包主要有几个步骤:
资源分类资产目录
存储原始资源文件。 系统在编译时不会编译该目录下的资源文件,因此无法通过ID访问。 如果要访问这些文件,需要指定要访问的文件名。 访问原始文件,它允许您以简单的字节流形式打开和读取与应用程序捆绑在一起的原始资源文件。 以下是读取本地json文件的示例:
StringBuilder sb = new StringBuilder();
AssetManager assets = getAssets();
try {
InputStream open = assets.open(“xxx.json”);
//使用一个转换流转换为字符流进行读取
InputStreamReader inputStreamReader = new InputStreamReader(open);
//缓冲字符流
BufferedReader reader = new BufferedReader(inputStreamReader);
String readLine;
while((readLine = reader.readLine())!=null){
sb.append(readLine);
}
String s = sb.toString();
} catch (IOException e) {
e.printStackTrace();
}
我们来看看一个典型的项目中asset目录下都放了什么。
资源目录
存储可编译的资源文件(原始文件除外)。 编译时,系统会自动在R.java文件中生成资源文件的id。 您可以通过R.xxx.id访问该资源。
目录资源类型
/
用于定义属性动画的 xml
动画/
用于定义补间动画的xml(属性动画也可以在这里定义)
颜色/
颜色状态列表 xml
/
位图文件(.9.png、.png、.jpg、.gif)
/
不同启动器图标密度的可绘制文件
/
用于定义用户界面布局的 XML 文件
菜单/
用于定义应用程序菜单(例如选项菜单、上下文菜单或子菜单)的 XML 文件
/
包含简单值(例如字符串、整数和颜色)的 XML 文件
XML/
任何可在运行时通过调用 .() 读取的 XML 文件。 各种XML配置文件(例如可搜索的配置)必须保存在此处。
字体/
具有扩展名(例如 .ttf、.otf 或 .ttc)的字体文件,或包含元素的 XML 文件
生的/
任何需要以其原始形式保存的文件
编译资源文件带来的好处
编译资源有以下两个优点:
生成资源索引表
首先,我们看一张图片。 这是.arsc的结构图。
整个 .arsc 由一系列块组成。 每个块都有一个标头来描述块的元数据。
<resources>
<string name="app_name">ABCstring>
resources>
生成 R 文件和资源 id
首先看一下R文件的结构图。 每个资源文件对应一个静态内部类。 与前面提到的res文件目录结构相比,每个静态内部类中的一个静态常量定义了一个资源标识符。
或这个:
public static final class layout {
public static final int main=0x7f030000;
}
最终 int main=; 表示目录中的main.xml 文件。 id中的最高字节代表id,第二高字节代表类型的id,最后一个字节代表当前类型中出现的序号。
资源文件只能以小写字母和下划线作为首字母,并且只能是 az、0-9 或 _。 后面的名称中不能出现字符,否则会报错。
当我们向对应的res资源目录添加一个资源文件时,对应的R文件中的静态内部类中会自动生成一个静态常量,用于对添加的文件进行索引。
在布局文件中,当我们需要为组件添加id属性时,可以使用@+id/,+表示为R文件中名为id的内部类添加一条记录。 如果这个id不存在,会先生成。
资源文件打包流程
讲完资源文件的一些基本信息,相信大家对apk包中的资源文件有了更加清晰的认识。 接下来我们来说说资源文件是如何打包成apk的。 这个过程非常复杂,需要很好的理解和记忆。
资源打包工具在编译应用资源之前会创建一个资源表。 应用资源编译完成后,这个资源表包含了资源的所有信息,然后可以根据这个资源表生成资源索引文件.arsc。
解析.xml
获取应用程序的包名来编译资源等,有了包名就可以创建资源表,即。
添加引用的资源包
通常编译一个apk包时,至少会涉及到两个资源包。 一个是引用的系统资源包,其中包含了很多系统级的资源,比如众所周知的四种布局等以及一些属性等,另一个是当前正在编译的应用程序的资源包。
收集资源文件
在编译应用程序资源之前,aapt会创建对象来收集当前需要编译的资源文件。 这些资源文件保存在该类的成员变量mRes中。
将采集到的资源添加到资源表中
我们在之前的基础上添加了资源。 在此步骤中,我们将向 . 我们最终会根据这个资源表生成.arsc资源索引表。 回头看一下arsc文件的结构图,它也有一个。
本步骤中资源表中收集的资源不包括在内,因为资源需要编译后才能添加到资源表中。
编译资源
描述了一些比较简单的轻量级资源,比如//dimen等,这些资源是在编译过程中收集的。
为包资源分配 id
资源下,除了 之外,还有一些其他特殊资源。 这些资源为自己定义了一些特殊的值,比如 的属性,其取值范围为 和 ,相当于定义了两个包 和 。
在编译其他非类资源之前,我们需要给之前收集到的bag资源分配资源id,因为它可能会被其他非类资源引用。
编译xml文件
前面的六个步骤已经为您编译 xml 文件做好了准备,并收集了 xml 所需的所有资源。 现在可以开始编译xml文件了,比如动画等。编译xml文件可以分为四个步骤
解析xml文件
此步骤会将 xml 文件转换为一系列树形结构,每个树形结构代表一个 xml 元素。 解析完成后,就可以得到一个根节点,然后基于这个根节点完成下面的操作。
给出属性名称 id
在此步骤中,资源 ID 被分配给每个 XML 元素的属性名称。 例如,控件有两个属性: 和 。 这里,资源ID被分配给这些属性名称。 对于系统资源包来说,这些属性名就是它定义的一系列包资源,并且在编译时就已经分配了资源ID。
对于每个xml文件,从根节点开始为属性名分配资源id,然后递归地为每个子节点的属性名分配资源id,直到每个节点的属性名都有资源id。
解析属性值
这一步是上一步的进一步发展。 上一步为每个属性分配一个 id。 这一步解析属性对应的值。 比如刚才的这个,会解析它的width和sum的值,可能是也可能不是。
展平 xml 文件
要将 xml 文件压平并将其转换为二进制格式,有以下步骤:
收集带有资源 ID 的属性名称字符串并将它们放入数组中。 这些收集到的属性名字符串存储在字符串资源池中,与收集到的资源id数组一一对应。 收集xml文件中的所有其他字符串,即不带资源ID的字符串,并将其写入xml文件头。 最终编译的xml二进制文件由一系列块组成。 每个chunk都有一个来描述Meta信息。 写入资源池字符串,将第一步、第二步收集的内容写入池中,即将资源id写入之前提到的arsc文件结构中的全局字符串资源池中,将所有资源的ID写入收集并生成时使用,对应arsc文件的结构。扁平化xml文件意味着替换每个xml元素中的字符串。 这些字符串要么替换为字符串资源池中的索引,要么替换为具有类型的另一个值,以生成资源的资源符号。
这里生成资源符号,为后续生成R文件做准备。 前面的操作将所有收集到的资源文件按照类型(即对象)保存在资源表中。 这里aapt只需要遍历每个类型,然后取出每个条目的名称即可。 根据其在对应类型中出现的顺序,可以计算出对应的资源ID,进而得到其资源符号。 资源符号=名称+资源id
根据资源ID生成资源索引表
这里我们将生成.arsc并再次反汇编其生成的步骤
根据集合类型字符串,如、、、、id等,当前编译的应用程序有几个,对应多组类型字符串,每组类型字符串都存储在其所属的文件中。 收集资源名称字符串,仍然以单位为单位。 例如,在 . 将.arsc文件格式中的格式逐级解析收集并写入资源索引表表头,即将资源项的值字符串写入资源池。 在上面的步骤 3 中,收集了所有值字符串。 ,这里直接写数据块即可,将第4步收集到的数据块写入到资源索引表中。
经过上述步骤,就生成了资源项索引表.arsc。
编译.xml文件
经过以上步骤,应用程序的所有资源就编译完成了。 这里,应用程序的配置文件.xml也被编译成二进制文件。
生成R文件
至此,我们已经知道了所有的资源以及它们对应的ID,接下来我们就可以愉快的将它们写入到R文件中了。 我们根据不同的类型将它们写入不同的静态内部类,就像之前介绍的R文件一样。 格式就是这样的。
打包到APK
所有资源文件编译生成后,就可以打包成apk了。
结论
终于写完了,整个资源文件的编译打包过程确实是一个非常复杂繁琐的过程。 在阅读过程中,您必须始终参考组织图,以便对这些文件有更清晰的了解。 资源文件在你的学习和工作中非常重要。 很多时候这些知识会被忽视,但是如果你有时间学习这些知识,对你来说将会是一个很大的进步。
画流程图
最后用流程图回顾一下整个过程。
参考