AAPT2(Android Asset Packaging Tool,Android 资源打包工具)是一种构建工具,Android Studio 和 Android Gradle 插件使用它来编译和打包应用的资源。AAPT2 会解析、索引并将资源编译为针对 Android 平台优化的二进制格式。
Android Gradle 插件 3.0.0 及更高版本默认启用 AAPT2。通常情况下,您无需自行调用 aapt2。但是,如果您更喜欢在终端中使用自己的构建系统而不是 Android Studio,则可以从命令行使用 AAPT2。您也可以从命令行调试与 AAPT2 相关的构建错误。为此,请在 Android SDK Build Tools 26.0.2 及更高版本中找到作为独立工具的 AAPT2。
要从命令行下载 Android SDK Build Tools,请使用 sdkmanager 并运行以下命令
sdkmanager "build-tools;build-tools-version"
下载 SDK Build Tools 后,您可以在 android_sdk/build-tools/version/ 中找到 AAPT2。
由于 Android SDK Build Tools 的修订版本发布频率不高,SDK Build Tools 中包含的 AAPT2 版本可能不是最新的。要获取最新版本的 AAPT2,请从 Google Maven 下载 AAPT2。
要在 Linux 或 Mac 上从命令行使用 AAPT2,请运行 aapt2 命令。在 Windows 上,请运行 aapt2.exe 命令。
AAPT2 通过启用增量编译来支持更快的资源编译。为了实现增量编译,资源处理被分为两个步骤
- 编译 (Compile):将资源文件编译为二进制格式。
- 链接 (Link):合并所有已编译的文件并将它们打包成一个单独的包。
这种分离有助于提高增量构建的性能。例如,如果只有一个文件发生了变化,您只需重新编译该文件即可。
从 Google Maven 下载 AAPT2
要获取未捆绑在构建工具中的最新版 AAPT2,请按以下步骤从 Google Maven 代码库下载 AAPT2
- 在 代码库索引中,导航至 com.android.tools.build > aapt2。
- 复制最新版 AAPT2 的版本名称。
将您复制的版本名称插入到以下 URL 中,并指定您的目标操作系统:https://dl.google.com/dl/android/maven2/com/android/tools/build/aapt2/ aapt2-version/aapt2-aapt2-version- [windows | linux | osx].jar
例如,要下载 Windows 版 3.2.0-alpha18-4804415,请使用:https://dl.google.com/dl/android/maven2/com/android/tools/build/aapt2/ 3.2.0-alpha18-4804415/aapt2-3.2.0-alpha18-4804415-windows.jar
在浏览器中导航至该 URL。AAPT2 将很快开始下载。
解压您刚刚下载的 JAR 文件。
JAR 文件应包含一个
aapt2可执行文件以及该可执行文件所依赖的一些库。
编译 (Compile)
AAPT2 支持编译所有 Android 资源类型,例如 drawable 和 XML 文件。调用 AAPT2 进行编译时,每次调用需传入单个资源文件作为输入。AAPT2 随后会解析该文件并生成一个扩展名为 .flat 的中间二进制文件。
当传入整个目录时,即使只有一个资源发生了变化,AAPT2 也会重新编译目录中的所有文件。虽然您可以使用 --dir 标志将包含多个资源文件的资源目录传递给 AAPT2,但这样做无法获得增量资源编译的好处。
输出文件类型会根据您提供的编译输入而有所不同,如下表所示
表 1. 编译的输入和输出文件类型
| 输入 | 输出 |
|---|---|
位于 res/values/ 目录中的 XML 资源文件(例如 字符串 (String) 和 样式 (Style)) |
扩展名为 *.arsc.flat 的资源表。 |
| 所有其他资源文件。 |
此外,所有 PNG 文件默认都会进行压缩 (crunching),并采用 |
AAPT2 输出的文件不是可执行文件,您稍后必须将这些二进制文件作为输入包含在链接阶段中以生成 APK。但是,生成的 APK 文件不是可以直接部署在 Android 设备上的可执行文件,因为它不包含 DEX 文件且未签名。
编译语法
使用 compile 的一般语法如下
aapt2 compile path-to-input-files [options] -o output-directory/
在以下示例中,AAPT2 分别编译了名为 values.xml 和 myImage.png 的资源文件
aapt2 compile project_root/module_root/src/main/res/values-en/strings.xml -o compiled/ aapt2 compile project_root/module_root/src/main/res/drawable/myImage.png -o compiled/
如表 1 所示,输出文件的名称取决于输入文件名及其父目录的名称。
对于上述以 strings.xml 文件作为输入的示例,aapt2 会自动将输出文件命名为 values-en_strings.arsc.flat。但是,存储在 drawable 目录中的已编译 drawable 文件被命名为 drawable_img.png.flat。
编译选项
有几个选项可以与 compile 命令一起使用,如表 2 所示
表 2. 编译命令选项
| 选项 | 描述 |
|---|---|
-o path
|
指定已编译资源的输出路径。 这是一个必需标志,因为您必须指定一个目录路径,以便 AAPT2 可以输出和存储已编译的资源。 |
--dir directory
|
指定要扫描资源的目录。 虽然您可以使用此标志通过单个命令编译多个资源文件,但它会使增量编译失效。因此,不应在大型项目中使用此标志。 |
--pseudo-localize
|
生成默认字符串的伪本地化版本,例如 en-XA 和 en-XB。 |
--no-crunch
|
禁用 PNG 处理。
如果您已经处理过 PNG 文件,或者正在创建不需要缩减文件大小的调试版本,请使用此选项。启用此选项会导致执行速度加快,但会增加输出文件大小。 |
--legacy
|
将使用早期版本 AAPT 时允许的错误视为警告。
此标志应用于意外的编译时错误。要解决使用 AAPT2 时可能发生的已知行为变化,请阅读使用 AAPT2 时的行为变化。 |
-zip file
|
file 是一个包含用于扫描资源的 res 目录的 ZIP 文件。 |
-output-text-symbols file
|
生成一个包含资源符号的文本文件 |
-preserve-visibility-of-styleables
|
如果指定,则对 styleables 应用与所有其他资源相同的可见性规则。否则,所有 styleables 均设为公开。 |
-visibility [public|private|default|]
|
将已编译资源的可见性设置为指定级别。 |
-trace-folder folder
|
生成一个 systrace JSON 跟踪片段到指定 |
-source-path path
|
将已编译资源文件的源文件路径设置为 |
-h
|
显示工具帮助。 |
-v
|
启用详细日志记录。 |
链接
在链接阶段,AAPT2 合并编译阶段生成的所有中间文件(例如资源表、二进制 XML 文件和已处理的 PNG 文件),然后将这些文件打包成单个 APK。此外,在此阶段还可以生成其他辅助文件,例如 R.java 和 ProGuard 规则文件。但是,生成的 APK 不包含 DEX 字节码且未签名。您无法将此 APK 部署到设备上。
如果您未使用 Android Gradle 插件从命令行构建应用,则可以使用其他命令行工具,例如使用 d8 将 Java 字节码编译为 DEX 字节码,使用 apksigner 对 APK 进行签名。
链接语法
使用 link 的一般语法如下
aapt2 link path-to-input-files [options] -o outputdirectory/outputfilename.apk --manifest AndroidManifest.xml
在以下示例中,AAPT2 合并了两个中间文件 drawable_Image.flat 和 values_values.arsc.flat,以及 AndroidManifest.xml 文件。AAPT2 将结果链接到 android.jar 文件,该文件持有 android 包中定义的资源
aapt2 link -o output.apk
-I android_sdk/platforms/android_version/android.jar
compiled/res/values_values.arsc.flat
compiled/res/drawable_Image.flat --manifest /path/to/AndroidManifest.xml -v
链接选项
您可以将以下选项与 link 命令一起使用
表 3. 链接命令选项
| 选项 | 描述 |
|---|---|
-o path
|
指定链接资源 APK 的输出路径。 这是一个必需标志,因为您必须指定可容纳链接资源的输出 APK 的路径。 |
--manifest file
|
指定要构建的 Android 清单文件的路径。 这是一个必需标志,因为清单文件包含有关您应用的必要信息,如包名称和应用 ID。 |
-I
|
提供平台 android 命名空间的属性,则此标志是必需的。 |
-A directory
|
指定要包含在 APK 中的 assets 目录。
您可以使用此目录来存储原始的、未处理的文件。要了解更多信息,请阅读访问原始文件。 |
-R file
|
将单个 .flat 文件传递给 link,在不使用 <add-resource> 标记的情况下使用 overlay 语义。
当您提供覆盖现有文件的资源文件时,将使用最后给出的冲突资源。 |
--package-id package-id
|
指定用于您应用的包 ID。
除非与 |
--allow-reserved-package-id
|
允许使用保留的包 ID。 保留的包 ID 是通常分配给共享库的 ID,范围为 0x02 到 0x7e(包含边界)。通过使用 此选项仅应用于 |
--java directory
|
指定生成 R.java 的目录。 |
--proguard proguard_options
|
生成 ProGuard 规则的输出文件。 |
--proguard-conditional-keep-rules
|
生成主 DEX 的 ProGuard 规则输出文件。 |
--no-auto-version
|
禁用自动样式和布局 SDK 版本控制。 |
--no-version-vectors
|
禁用矢量 drawable 的自动版本控制。仅在使用 Vector Drawable 库构建 APK 时使用此标志。 |
--no-version-transitions
|
禁用过渡资源的自动版本控制。仅在使用 Transition 支持库构建 APK 时使用此标志。 |
--no-resource-deduping
|
禁用跨兼容配置具有相同值的资源的自动去重。 |
--enable-sparse-encoding
|
启用资源条目的稀疏编码。这会减小 APK 大小、内存使用量和启动延迟,并略微增加启动后的单个资源查找时间。 |
-z
|
要求对标记为“建议”的字符串进行本地化。 |
-c config
|
提供逗号分隔的配置列表。
例如,如果您有对支持库的依赖,其中包含多种语言的翻译,您可以仅针对给定的语言配置(如英语或西班牙语)过滤资源。 您必须通过双字母 ISO 639-1 语言代码定义语言配置,后跟可选的双字母 ISO 3166-1-alpha-2 地区代码,前面带小写字母 'r'。例如,en-rUS。 |
--preferred-density density
|
允许 AAPT2 选择最匹配的密度并剥离所有其他密度。
应用中有几种像素密度限定符可供使用,例如 ldpi、hdpi 和 xhdpi。当您指定首选密度时,AAPT2 会选择并存储资源表中与该密度最匹配的项,并移除所有其他项。 |
--output-to-dir
|
将 APK 内容输出到由 -o 指定的目录。
如果使用此标志遇到任何错误,可以通过升级到 Android SDK Build Tools 28.0.0 或更高版本来解决。 |
--min-sdk-version min-sdk-version
|
设置 AndroidManifest.xml 使用的默认最低 SDK 版本。 |
--target-sdk-version target-sdk-version
|
设置 AndroidManifest.xml 使用的默认目标 SDK 版本。 |
--version-code version-code
|
指定在 AndroidManifest.xml 中不存在版本代码时注入其中的版本代码。 |
--version-name version-name
|
指定在 AndroidManifest.xml 中不存在版本名称时注入其中的版本名称。 |
--revision-code revision-code
|
指定在 AndroidManifest.xml 文件中不存在修订版本代码时注入其中的修订版本代码。 |
--replace-version
|
如果指定了 --version-code、--version-name 或 --revision-code,则这些值将替换清单中已有的任何值。默认情况下,如果清单已定义这些属性,则不会有任何更改。 |
--compile-sdk-version-nacodeme compile-sdk-version-name
|
指定在 AndroidManifest.xml 文件中不存在版本代码时注入其中的版本代码。 |
--compile-sdk-version-name compile-sdk-version-name
|
指定在 AndroidManifest.xml 文件中不存在版本名称时注入其中的版本名称。 |
--proto-format
|
以 Protobuf 格式生成已编译的资源。 适合作为 |
--non-final-ids
|
生成包含非 final 资源 ID 的 R.java。在 kotlinc 或 javac 编译期间,不会内联来自应用代码的 ID 引用。 |
--emit-ids path
|
在给定路径生成一个文件,其中包含资源类型名称及其 ID 映射的列表。这适合与 --stable-ids 一起使用。 |
--stable-ids outputfilename.ext
|
消耗使用 --emit-ids 生成的文件,其中包含资源类型名称及其分配的 ID 列表。
此选项允许在链接时删除或添加新资源时,已分配的 ID 保持稳定。 |
--custom-package package_name
|
指定生成 R.java 的自定义 Java 包。 |
--extra-packages package_name
|
生成相同的 R.java 文件,但具有不同的包名称。 |
--add-javadoc-annotation annotation
|
向所有生成的 Java 类添加 JavaDoc 注解。 |
--output-text-symbols path
|
在指定文件中生成一个包含 R 类资源符号的文本文件。
您必须指定输出文件的路径。 |
--auto-add-overlay
|
允许在不使用 <add-resource> 标记的情况下在叠加层中添加新资源。 |
--rename-manifest-package manifest-package
|
重命名 AndroidManifest.xml 文件中的包。 |
--rename-instrumentation-target-package instrumentation- target-package
|
更改 instrumentation 的目标包名称。
此选项应与 |
-0 extension
|
指定您不想压缩的文件的扩展名。 |
--split path:config[,config[..]]
|
基于一组配置拆分资源以生成不同版本的 APK。
您必须指定输出 APK 的路径以及配置集。 |
--proguard-main-dex file
|
用于主 DEX 的生成 ProGuard 规则的输出文件。 |
--proguard-minimal-keep-rules
|
生成最少的一组 ProGuard 保留规则。 |
--no-resource-removal
|
禁用自动移除没有默认值的资源。仅在构建运行时资源叠加层包时使用此选项。 |
-x
|
指定使用包标识符 0x01 的遗留标志。 |
--product products-list
|
指定要保留的产品名称的逗号分隔列表。 |
--no-xml-namespaces
|
从 AndroidManifest.xml 文件和 res/* 中的 XML 二进制文件中移除 XML 命名空间前缀和 URI 信息。 |
--shared-lib
|
生成共享的 Android 运行时库。 |
--static-lib
|
生成静态的 Android 库。 |
--no-static-lib-packages
|
将所有库资源合并到应用包下。 |
--no-proguard-location-reference
|
防止 ProGuard 规则文件引用源文件。 |
--private-symbols package-name
|
package-name 指定生成私有符号的 R.java 时使用的包名称。如果未指定,公共和私有符号将使用应用的包名称。 |
--override-styles-instead-of-overlaying
|
导致在 -R 资源中定义的样式替换之前的定义,而不是合并它们。 |
--rename-resources-package package-name
|
将资源表中的包重命名为 package-name。 |
--no-compress
|
不压缩任何资源。 |
--keep-raw-values
|
在 XML 文件中保留原始属性值。 |
--no-compress-regex regular-expression
|
不压缩匹配 regular-expression 的扩展名。使用 $ 符号表示行尾。使用区分大小写的 ECMAScript 正则表达式语法。 |
--warn-manifest-validation
|
将清单验证错误视为警告。 |
--exclude-configs qualifier[,qualifier[..]]
|
排除配置包含指定限定符的资源值。 |
--debug-mode
|
在清单的 application 节点中插入 android:debuggable="true",使应用程序即使在生产设备上也可以调试。 |
--strict-visibility
|
不允许具有不同可见性级别的叠加层。 |
--exclude-sources
|
以 Protobuf 格式生成资源时,不序列化源文件信息。 |
--trace-folder folder
|
生成 systrace JSON 跟踪片段到指定 folder。 |
--merge-only
|
仅合并资源而不验证资源引用。此标志仅应与 --static-lib 标志一起使用。 |
-h
|
显示帮助菜单。 |
-v
|
增加输出的详细程度。 |
Dump
dump 用于打印有关您使用 link 命令生成的 APK 的信息。
Dump 语法
使用 dump 的一般语法如下
aapt2 dump sub-command filename.apk [options]
以下示例打印来自指定 APK 资源表的内容
aapt2 dump resources output.apk
Dump 子命令
使用 dump 命令指定以下子命令之一
Table 4. Dump 子命令
| 子命令 | 描述 |
|---|---|
apc
|
打印编译期间生成的 AAPT2 容器 (APC) 的内容。 |
badging
|
打印从 APK 清单中提取的信息。 |
configurations
|
打印 APK 中资源使用的每种配置。 |
overlayable
|
打印 APK 的可叠加资源。 |
packagename
|
打印 APK 的包名称。 |
permissions
|
打印从 APK 清单中提取的权限。 |
strings
|
打印 APK 资源表字符串池的内容。 |
styleparents
|
打印 APK 中使用的样式的父项。 |
resources
|
打印 APK 资源表的内容。 |
xmlstrings
|
打印来自 APK 已编译 XML 的字符串。 |
xmltree
|
打印 APK 已编译 XML 的树。 |
Dump 选项
将以下选项与 dump 一起使用
Table 5. Dump 选项
| 选项 | 描述 |
|---|---|
--no-values
|
显示资源时禁止输出值。 |
--file file
|
指定要从 APK 转储的文件作为参数。 |
-v
|
增加输出的详细程度。 |
Diff
使用 diff 比较两个 APK 并识别它们之间的任何差异。
Diff 语法
使用 diff 的一般语法如下
aapt2 diff first.apk second.apk
diff 命令没有选项。
优化
optimize 用于在将已合并的资源和 resources.arsc 打包到 APK 之前对其进行优化。这种优化可以将 APK 大小减少约 1-3%,具体取决于所使用的资源的大小和数量。
Optimize 语法
使用 optimize 的一般语法如下
aapt2 optimize options file[,file[..]]
以下示例优化 input.apk 中的资源并在 output.apk 中创建一个新的优化 APK。它用更紧凑的表示形式替换了通常的平面表表示形式,从而减小了 APK 大小、内存使用量和启动延迟,并略微增加了启动后的单个资源查找时间。
aapt2 optimize -o output.apk --enable-sparse-encoding input.apk
Optimize 选项
您可以将以下选项与 optimize 一起使用
Table 6. Optimize 选项
| 选项 | 描述 |
|---|---|
-o path
|
指定链接资源 APK 的输出路径。
这是一个必需标志,因为您必须指定可容纳链接资源的输出 APK 的路径。 |
-d directory
|
指定拆分的输出目录路径。 |
-x path
|
指定 XML 配置文件的路径。 |
-p
|
打印多 APK 工件并退出。 |
--target-densities density[,density[..]]
|
指定 APK 优化的屏幕密度列表(以逗号分隔)。在给定密度的设备上不会使用的所有资源都将从 APK 中删除。 |
--resources-config-path path
|
指定包含资源列表和针对每个资源的指令的 格式:type/resource_name#[directive][,directive] |
-c config[,config[..]]
|
指定要包含的配置列表(以逗号分隔)。默认值为所有配置。 |
--split path:config[,config[..]]
|
基于一组配置拆分资源以生成不同版本的 APK。
您必须指定输出 APK 的路径以及配置集。 |
--keep-artifacts artifact[,artifact[..]]
|
指定要保留的工件列表(以逗号分隔)。如果未指定,则保留所有工件。 |
--enable-sparse-encoding
|
启用资源条目的稀疏编码。这会减小 APK 大小、内存使用量和启动延迟,并略微增加启动后的单个资源查找时间。 |
--collapse-resource-names
|
将资源名称折叠为键字符串池中的单个值。资源使用 --resources-config-path 指定文件中的 no_collapse 指令豁免。 |
--shorten-resource-paths
|
缩短 APK 内资源的路径。 |
--resource-path-shortening-map path
|
指定输出旧资源路径到缩短路径的映射文件的路径。 |
-v
|
增加输出的详细程度。 |
-h
|
显示工具帮助。 |
Convert
默认情况下,AAPT compile 命令将资源编译为适合 APK 的二进制格式。也可以通过指定 --proto-format 来指定适合 AAB 的 protobuf 格式。convert 命令在两种格式之间转换 APK。
Convert 语法
使用 convert 的一般语法如下
aapt2 convert -o output-file options file[,file[..]]
以下示例转换 input.apk 中的资源,并创建一个包含 protobuf 格式资源的新 APK output.apk。它用更紧凑的表示形式替换了通常的平面表表示形式,从而减小了 APK 大小、内存使用量和启动延迟,并略微增加
aapt2 convert -o output.apk --output-format proto --enable-sparse-encoding input.apk
Convert 选项
将以下选项与 convert 一起使用
Table 7. Convert 选项
| 选项 | 描述 |
|---|---|
-o path
|
指定链接资源 APK 的输出路径。 这是一个必需标志,因为您必须指定可容纳链接资源的输出 APK 的路径。 |
--output-format [proto|binary]
|
输出格式。接受的值为 proto 和 binary。未设置时,默认为 binary。 |
--enable-sparse-encoding
|
启用资源条目的稀疏编码。这会减小 APK 大小、内存使用量和启动延迟,并略微增加启动后的单个资源查找时间。 |
--keep-raw-values
|
在 XML 文件中保留原始属性值。 |
-v
|
增加输出的详细程度。 |
-h
|
显示工具帮助。 |
守护进程模式 (Daemon mode)
AAPT 2.19 版本引入了用于发出命令的守护进程模式。守护进程模式允许您在单个 AAPT 会话中输入多个命令。
守护进程语法
使用以下命令启动守护进程模式
aapt2 daemon
一旦守护进程模式运行,您就可以输入命令。命令的每个参数必须在单独的一行上,命令末尾有一个空行。通过键入 Control+D 退出守护进程模式。
考虑以下单独的 compile 命令
aapt2 compile project_root/module_root/src/main/res/values-en/strings.xml -o compiled/ aapt2 compile project_root/module_root/src/main/res/drawable/myImage.png -o compiled/
这些命令可以在守护进程模式下输入为
aapt2 daemon Ready compile project_root/module_root/src/main/res/values-en/strings.xml -o compiled/ Done compile project_root/module_root/src/main/res/drawable/myImage.png -o compiled/ Done ^D Exiting daemon
守护进程模式选项
守护进程模式的唯一选项是 --trace-folder folder,它将 systrace JSON 跟踪片段生成到指定 folder。
版本
使用 version 命令确定您正在使用的 AAPT2 版本
aapt2 version Android Asset Packaging Tool (aapt) 2.19-8678579
使用 AAPT2 时的行为变化
在 AAPT2 之前,AAPT 是 Android 资源打包工具的默认版本,现已弃用。虽然 AAPT2 应该能立即用于旧项目,但本节介绍了您应该注意的一些行为变化。
Android 清单中的元素层次结构
在以前版本的 AAPT 中,嵌套在 AndroidManifest.xml 文件中不正确节点中的元素会被忽略或导致警告。例如,考虑以下示例
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myname.myapplication"> <application ... <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <action android:name="android.intent.action.CUSTOM" /> </activity> </application> </manifest>
以前版本的 AAPT 会直接忽略放错位置的 <action> 标记。
使用 AAPT2,您会收到以下错误
AndroidManifest.xml:15: error: unknown element <action> found.
要解决此问题,请确保您的清单元素嵌套正确。有关更多信息,请阅读应用清单概览。
资源声明
您不能再从 name 属性指明资源类型。以下示例错误地声明了一个 attr 资源项
<style name="childStyle" parent="parentStyle"> <item name="attr/my_attr">@color/pink</item> </style>
以这种方式声明资源类型会导致以下构建错误
Error: style attribute 'attr/attr/my_attr (aka my.package:attr/attr/my_attr)' not found.
要解决此错误,请使用 type="attr" 显式声明类型
<style name="childStyle" parent="parentStyle"> <item type="attr" name="my_attr">@color/pink</item> </style>
此外,声明 <style> 元素时,其父项也必须是样式资源类型。否则,您会得到类似以下内容的错误
Error: (...) invalid resource type 'attr' for parent of style
不正确使用 @ 资源引用符号
当您省略或错误放置资源引用符号 (@) 时,AAPT2 会抛出构建错误。例如,如果您在指定样式属性时省略了该符号
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> ... <!-- Note the missing '@' symbol when specifying the resource type. --> <item name="colorPrimary">color/colorPrimary</item> </style>
构建模块时,AAPT2 会抛出以下构建错误
ERROR: expected color but got (raw string) color/colorPrimary
此外,如果您在从 android 命名空间访问资源时错误地包含了该符号
... <!-- When referencing resources from the 'android' namespace, omit the '@' symbol. --> <item name="@android:windowEnterAnimation"/>
构建模块时,AAPT2 会抛出以下构建错误
Error: style attribute '@android:attr/windowEnterAnimation' not found
不正确的库配置
如果您的应用依赖于使用旧版本 Android SDK Build Tools 构建的第三方库,您的应用可能会在运行时崩溃,而不会显示任何错误或警告。此崩溃可能是因为在库创建过程中,R.java 字段被声明为 final。结果,所有资源 ID 都会在库的类中内联。
AAPT2 依赖于在构建应用时能够重新为库资源分配 ID。如果库假设 ID 是 final 并将它们内联在库 DEX 中,则会出现运行时不匹配。
要解决此错误,请联系库作者使用最新版本的 Android SDK Build Tools 重新构建该库,并重新发布该库。