前言

从Android Studio 3.0开始,google默认开启了aapt2作为资源编译的编译器,aapt2的出现,为资源的增量编译提供了支持。当然使用过程中也会遇到一些问题,我们可以通过在gradle.properties中配置android.enableAapt2=false来关闭aapt2。

使用方式

aapt2将原先的资源编译打包过程拆分成了两部分,即编译和链接,这样就能很好的提升资源的编译性能,比如只有一个资源文件发送改变时,你只需要重新编译改变的文件,然后将其与其他未改变的资源进行链接即可。而之前的aapt是将所有资源进行merge,merge完后将所有资源进行编译,产生一个资源ap_文件,该文件是一个压缩包,这样带来的后果就是即使只改变了一个资源文件,也要进行全量编译。这篇文章主要讲一下aapt2的compile的流程,link的流程比较复杂,后续讲解。

首先来看看其compile命令的使用姿势。

1
2
3
4
5
6
7
8
9
10
aapt2 compile [options] -o arg files...
Options:
-o arg Output path
--dir arg Directory to scan for resources
--pseudo-localize Generate resources for pseudo-locales (en-XA and ar-XB)
--no-crunch Disables PNG processing
--legacy Treat errors that used to be valid in AAPT as warnings
-v Enables verbose logging
-h Displays this help menu

编译过程使用aapt2 compile命令,它有一系列的参数。

-o参数指定了编译文件输出的路径,这个参数可以是目录,也可以是文件,取决于输入的资源文件是目录还是文件。假如输入的是目录,则输出的是个zip压缩包,参数值必须是个文件;输入的是单个资源文件,则输出的是一个flat文件,参数值必须是个目录,输出的文件名由aapt2生成。
–dir用于指定扫描的资源目录,该参数用于资源的批量编译,不用指定一个个文件单独编译。
–pseudo-localize参数在aapt中也有,主要是生成伪本地化信息,如en-XA和ar-XB
–no-crunch表示禁用png文件的压缩等处理
–legacy表示将aapt中认为是警告的地方作为错误抛出,并终止编译
-v参数将开启编译日志的输出
-h参数则会输出上面的使用帮助信息

用Android Studio 3.0新建一个新的空项目。我们尝试使用命令行进行资源编译。打开终端,进入当前项目根目录

1
aapt2 compile -o ./build ./app/src/main/res/values/strings.xml

以上命令将string.xml进行了编译,最终编译产物位于项目根目录下的build目录中,其文件名为该文件上级目录名_该文件名.arsc.flat,即values_strings.arsc.flat,这是values文件夹下的文件的命名,可以看到xml后缀变成了arsc,这是代码中覆盖文件后缀导致的。我们来看下其他文件,我们编译一个布局文件

1
aapt2 compile -o ./build ./app/src/main/res/layout/activity_main.xml

以上命令会编译产生layout_activity_main.xml.flat文件,即上级文件目录名_该文件名.flat,这是非values资源的命名方式

看下图片资源编译会产生什么

1
aapt2 compile -o ./build ./app/src/main/res/mipmap-xhdpi/ic_launcher.png

以上命令会编译产生mipmap-xhdpi_ic_launcher.png.flat文件,命名方式和layout一样

将上面三个文件连起来一起编译就是

1
aapt2 compile -o ./build ./app/src/main/res/mipmap-xhdpi/ic_launcher.png ./app/src/main/res/layout/activity_main.xml ./app/src/main/res/values/strings.xml

上面是单个文件的编译方式,下面看看直接编译整个目录

1
aapt2 compile -o ./build/res.apk --dir ./app/src/main/res/

该命令为产生一个res.apk的文件,该文件是一个zip压缩包,里面包含了编译好的资源文件,如下图所示

将以上流程总结为一张图

flat文件结构解析

那么编译产生的flat文件到底是什么东西呢,不同类型的文件其flat格式是不同的,这里以普通文件举例,即compileFile产生的flat文件(compilePng、compileXml产生的flat文件和compileFile是类似的),先来看一张结构图

从上图可以看到,flat文件其实就是一种特定的文件格式,文件开头4个字节(32位)表示当前flat文件中的文件个数k,紧跟着8个字节(64位)的数据,表示后面紧跟着的protobuf数据的大小n,接着就是跟着n个字节的protobuf数据,接着是8个字节(64位)的真实数据大小m,紧跟在后面的就是m个字节的真实数据。依次循环k次这种文件结构,最终就是flat文件了。

其中protobuf部分的数据Format.proto的定义如下,非values资源使用的是CompiledFile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
syntax = "proto2";
option optimize_for = LITE_RUNTIME;
package aapt.pb;
message ConfigDescription {
optional bytes data = 1;
optional string product = 2;
}
message StringPool {
optional bytes data = 1;
}
message CompiledFile {
message Symbol {
optional string resource_name = 1;
optional uint32 line_no = 2;
}
optional string resource_name = 1;
optional ConfigDescription config = 2;
optional string source_path = 3;
repeated Symbol exported_symbols = 4;
}
message ResourceTable {
optional StringPool string_pool = 1;
optional StringPool source_pool = 2;
optional StringPool symbol_pool = 3;
repeated Package packages = 4;
}
message Package {
optional uint32 package_id = 1;
optional string package_name = 2;
repeated Type types = 3;
}
message Type {
optional uint32 id = 1;
optional string name = 2;
repeated Entry entries = 3;
}
message SymbolStatus {
enum Visibility {
Unknown = 0;
Private = 1;
Public = 2;
}
optional Visibility visibility = 1;
optional Source source = 2;
optional string comment = 3;
optional bool allow_new = 4;
}
message Entry {
optional uint32 id = 1;
optional string name = 2;
optional SymbolStatus symbol_status = 3;
repeated ConfigValue config_values = 4;
}
message ConfigValue {
optional ConfigDescription config = 1;
optional Value value = 2;
}
message Source {
optional uint32 path_idx = 1;
optional uint32 line_no = 2;
optional uint32 col_no = 3;
}
message Reference {
enum Type {
Ref = 0;
Attr = 1;
}
optional Type type = 1;
optional uint32 id = 2;
optional uint32 symbol_idx = 3;
optional bool private = 4;
}
message Id {
}
message String {
optional uint32 idx = 1;
}
message RawString {
optional uint32 idx = 1;
}
message FileReference {
optional uint32 path_idx = 1;
}
message Primitive {
optional uint32 type = 1;
optional uint32 data = 2;
}
message Attribute {
message Symbol {
optional Source source = 1;
optional string comment = 2;
optional Reference name = 3;
optional uint32 value = 4;
}
optional uint32 format_flags = 1;
optional int32 min_int = 2;
optional int32 max_int = 3;
repeated Symbol symbols = 4;
}
message Style {
message Entry {
optional Source source = 1;
optional string comment = 2;
optional Reference key = 3;
optional Item item = 4;
}
optional Reference parent = 1;
optional Source parent_source = 2;
repeated Entry entries = 3;
}
message Styleable {
message Entry {
optional Source source = 1;
optional string comment = 2;
optional Reference attr = 3;
}
repeated Entry entries = 1;
}
message Array {
message Entry {
optional Source source = 1;
optional string comment = 2;
optional Item item = 3;
}
repeated Entry entries = 1;
}
message Plural {
enum Arity {
Zero = 0;
One = 1;
Two = 2;
Few = 3;
Many = 4;
Other = 5;
}
message Entry {
optional Source source = 1;
optional string comment = 2;
optional Arity arity = 3;
optional Item item = 4;
}
repeated Entry entries = 1;
}
message Item {
optional Reference ref = 1;
optional String str = 2;
optional RawString raw_str = 3;
optional FileReference file = 4;
optional Id id = 5;
optional Primitive prim = 6;
}
message CompoundValue {
optional Attribute attr = 1;
optional Style style = 2;
optional Styleable styleable = 3;
optional Array array = 4;
optional Plural plural = 5;
}
message Value {
optional Source source = 1;
optional string comment = 2;
optional bool weak = 3;
optional Item item = 4;
optional CompoundValue compound_value = 5;
}

以上是非values资源产生的flat文件的文件格式,而values类型的资源,其实是以上数据格式的阉割版,即只有protobuf部分的数据结构,其结构为上面proto格式部分的ResourceTable部分

gradle中compile流程

gradle中主要由OutOfProcessAaptV2和AaptV2CommandBuilder类承载aapt2的执行,关键函数如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@Nullable
@Override
protected CompileInvocation makeCompileProcessBuilder(@NonNull CompileResourceRequest request)
throws AaptException {
Preconditions.checkArgument(request.getInput().isFile(), "!file.isFile()");
Preconditions.checkArgument(request.getOutput().isDirectory(), "!output.isDirectory()");
return new CompileInvocation(
new ProcessInfoBuilder()
.setExecutable(getAapt2ExecutablePath())
.addArgs("compile")
.addArgs(AaptV2CommandBuilder.makeCompile(request)),
new File(
request.getOutput(),
Aapt2RenamingConventions.compilationRename(request.getInput())));
}
public static ImmutableList<String> makeCompile(@NonNull CompileResourceRequest request) {
ImmutableList.Builder<String> parameters = new ImmutableList.Builder();
if (request.isPseudoLocalize()) {
parameters.add("--pseudo-localize");
}
if (!request.isPngCrunching()) {
// Only pass --no-crunch for png files and not for 9-patch files as that breaks them.
String lowerName = request.getInput().getPath().toLowerCase(Locale.US);
if (lowerName.endsWith(SdkConstants.DOT_PNG)
&& !lowerName.endsWith(SdkConstants.DOT_9PNG)) {
parameters.add("--no-crunch");
}
}
parameters.add("--legacy");
parameters.add("-o", request.getOutput().getAbsolutePath());
parameters.add(request.getInput().getAbsolutePath());
return parameters.build();
}

很简单,就是简单的命令拼接,和上面说的是完全一样的。

总结

开启了aapt2后,资源的增量编译会加速编译速度,但是有些场景aapt2并不是很合适,因此必要的情况下,建议关闭aapt2,比如jenkins上构建时,我们并不需要增量编译,因此可以关闭,可以通过gradle参数达到关闭的效果,命令如下

1
gradle assembleRelease -Pandroid.enableAapt2=false

简单总结了几种不适合使用aapt2的场景

  • 插件化和热修复中,需要使用public.xml的场景
  • 构建过程,需要动态增删改资源的场景,如删除一部分线上不应该出现的资源
http://fucknmb.com/2017/10/31/aapt2%E8%B5%84%E6%BA%90compile%E8%BF%87%E7%A8%8B/

aapt2 资源 compile 过程相关推荐

  1. 【Android 安装包优化】资源混淆 ( AAPT2 资源编译工具 | resources.arsc 资源映射表 工作机制 )

    文章目录 一.AAPT2 资源编译工具 二.resources.arsc 资源映射表 工作机制 三.参考资料 一.AAPT2 资源编译工具 资源的编译 , 生成 R.java 文件 , 都是通过 AA ...

  2. aapt2资源打包工具

    AAPT2 AAPT2(Android资源打包工具)是一种构建工具,Android Studio 和 Android Gradle 插件使用它来编译和打包应用的资源.AAPT2 会解析资源.为资源编制 ...

  3. SDN控制器的资源收集过程—Vecloud

    1.网元资源信息收集 控制器和转发器的控制通道建立完成后,转发器主动向控制器发起控制协议连接,控制协议为openflow等协议,认证后建立. 接下来,转发器向控制器注册信息:接口资源.标签信息.VLA ...

  4. android 资源匹配,Android资源匹配过程(二)

    上一篇文章了解了Android资源标签属性及优先级 后,下面我们来看资源的具体匹配规则. 下面以一个实际例子作为说明. 假设某App中的drawable资源有如下几种选项: drawable/ dra ...

  5. 估算活动资源-规划过程组

    估算活动资源是估算执行各项活动所需的材料.人员.设备或用品的种类和数量的过程. 本过程的主要作用是,明确完成活动所需的资源种类.数量和特性, 以便做出更准确的成本 和持续时间估算. 估算活动资源    ...

  6. 数据中心服务在资源整合过程的实践

    首先下个定义,这里的资源整合,是指在包括实体文件与数据信息在内的同类资源的整合. 一些企业或一些项目在经历过一段时间内,经常有需求把已经有的一些资源或者其它公司提供的一些资源根据需要进行整合.现实很具 ...

  7. aapt2 生成资源 public flag 标记

    前言 之前写过一篇aapt2适配之资源id固定,该文章介绍了如何使用aapt2固定资源id,其实这篇文章是对该文章的一点补充,主要介绍如何在固定id的同时,将该资源进行导出,打上public标记,供其 ...

  8. aapt2 适配之资源 id 固定

    前言 资源id的固定在热修复和插件化中极其重要.在热修复中,构建patch时,需要保持patch包的资源id和基线包的资源id一致:在插件化中,如果插件需要引用宿主的资源,则需要将宿主的资源id进行固 ...

  9. 3.0 Appt2的异常问题 不一定需要关闭才能通过编译

    正如标题所言,Android studio3.0并不是真的如网上所说,关闭就是最好的解决方式: 如果出现Appt2问题,请不要着急寻求度娘的帮助,如果能够自己先去找问题的根本,然后分享出来,比起度娘五 ...

最新文章

  1. 能在xcode5中开发基于IOS7sdk的应用程序兼容ios4.3之后的系统吗?
  2. 音视频技术开发周刊 | 157
  3. 剑指Offer之二叉树中的和为某一路径的值
  4. Atitit 物联网体系图 感知层 条码:物联网的第一代身份证 65二维码 4 电子标签:物联网的第二代身份证 78 4 传感器:物联网的神经元 92 4 自动识别技术 光学字符识别技术
  5. 解决Keil4与Keil5在同系统不能共存的问题
  6. php CI框架单元测试
  7. Pocket PC、Pocket PC phone、Smartphone的区别
  8. 手机,电脑都能用的,整人,恶搞代码连接,“你不会百度一下吗”教你用百度
  9. RAID容量在线计算器
  10. 解字谜:黑白皆算,对我等众猿而言中央C所在位置数优剃爱肤杠吧爱慕帝贰亿次的值是?...
  11. vmstate内存事件详解
  12. Codeforces1379 B. Dubious Cyrpto(枚举)
  13. 自带流量的免费微信编辑器推荐
  14. 计算机专业简历教育背景怎么写,简历中教育背景怎么写?填写教育背景注意事项...
  15. 【自己写全景】TreeJs实现全景图
  16. 文件管理android2.3,Tomi文件管理器下载 v2.3.4 安卓版
  17. matlab 求矩阵秩,求矩阵秩的两种方法及MATLAB的应用
  18. php工具箱安装mysql_php工具箱升级自带mysql到mysql5.7
  19. 金仓数据库KingbaseES客户端编程接口指南-DCI(3. DCI 工程配置)
  20. 这些常见的安全漏洞和修复方法你知道吗?

热门文章

  1. java全面的知识体系结构总结
  2. iOS传值之代理传值
  3. Visual LISP 第5章 编辑源程序代码(1)文本编辑工具
  4. 图像处理之直方图均衡MATLAB代码实现
  5. shell中条件判断语法与判断条件小结
  6. Python:C语言扩展
  7. Linux sem_init函数用法
  8. 计算机桌面图标有背影,桌面图标有背影怎么解决
  9. 【随笔】深度学习的数据增强还分在线和离线?
  10. [一维粒子模拟 version3.6]renormalization