Android.bp如下所示
android_app {
name: "xxx-res",
certificate: "platform",
platform_apis: true,
// Soong special-cases framework-res to install this alongside
// the libraries at /system/framework/framework-res.apk.
// Generate private symbols into the com.android.internal.R class
// so they are not accessible to 3rd party apps.
aaptflags: [
// Framework doesn't need versioning since it IS the platform.
"--no-auto-version",
// Allow overlay to add resource
"--auto-add-overlay",
"--allow-reserved-package-id",
// Add for xxx
"--package-id 0x0a",
"--private-symbols",
"com.xxx.internal",
],
owner: "xxx",
// Create package-export.apk, which other packages can use to get
// PRODUCT-agnostic resource data like IDs and type definitions.
export_package_resources: true,
}
报错如下,
FAILED: out_sys/soong/.intermediates/vendor/xxx/proprietary/framework/base/core/res/xxx-res/android_common/package-res.apk out_sys/soong/.intermediates/vendor/xxx/proprietary/framework/base/core/res/xxx-res/android_common/gen/proguard.options out_sys/soong/.intermediates/vendor/xxx/proprietary/framework/base/core/res/xxx-res/android_common/gen/android/R.srcjar out_sys/soong/.intermediates/vendor/xxx/proprietary/framework/base/core/res/xxx-res/android_common/R.txt out_sys/soong/.intermediates/vendor/xxx/proprietary/framework/base/core/res/xxx-res/android_common/extra_packages
rm -rf out_sys/soong/.intermediates/vendor/xxx/proprietary/framework/base/core/res/xxx-res/android_common/gen/aapt2/R && out_sys/host/linux-x86/bin/aapt2 link -o out_sys/soong/.intermediates/vendor/xxx/proprietary/framework/base/core/res/xxx-res/android_common/package-res.apk --no-auto-version --auto-add-overlay --package-id 0x0a --private-symbols com.xxx.internal --no-static-lib-packages --manifest out_sys/soong/.intermediates/vendor/xxx/proprietary/framework/base/core/res/xxx-res/android_common/manifest_fixer/AndroidManifest.xml --min-sdk-version 34 --target-sdk-version 34 --version-code 34 --version-name 14 -I out_sys/soong/.intermediates/frameworks/base/core/res/framework-res/android_common/package-res.apk --product default -c en_US,zh_CN,zh_TW,es_ES,pt_BR,ru_RU,fr_FR,de_DE,tr_TR,vi_VN,ms_MY,in_ID,th_TH,it_IT,ar_EG,hi_IN,bn_IN,ur_PK,fa_IR,pt_PT,nl_NL,el_GR,hu_HU,tl_PH,ro_RO,cs_CZ,ko_KR,km_KH,iw_IL,my_MM,pl_PL,es_US,bg_BG,hr_HR,lv_LV,lt_LT,sk_SK,uk_UA,de_AT,da_DK,fi_FI,nb_NO,sv_SE,en_GB,hy_AM,zh_HK,et_EE,ja_JP,kk_KZ,sr_RS,sl_SI,ca_ES, --java out_sys/soong/.intermediates/vendor/xxx/proprietary/framework/base/core/res/xxx-res/android_common/gen/aapt2/R --proguard out_sys/soong/.intermediates/vendor/xxx/proprietary/framework/base/core/res/xxx-res/android_common/gen/proguard.options --output-text-symbols out_sys/soong/.intermediates/vendor/xxx/proprietary/framework/base/core/res/xxx-res/android_common/R.txt @out_sys/soong/.intermediates/vendor/xxx/proprietary/framework/base/core/res/xxx-res/android_common/aapt2/res.list && out_sys/host/linux-x86/bin/soong_zip -write_if_changed -jar -o out_sys/soong/.intermediates/vendor/xxx/proprietary/framework/base/core/res/xxx-res/android_common/gen/android/R.srcjar -C out_sys/soong/.intermediates/vendor/xxx/proprietary/framework/base/core/res/xxx-res/android_common/gen/aapt2/R -D out_sys/soong/.intermediates/vendor/xxx/proprietary/framework/base/core/res/xxx-res/android_common/gen/aapt2/R &&out_sys/host/linux-x86/bin/extract_jar_packages -i out_sys/soong/.intermediates/vendor/xxx/proprietary/framework/base/core/res/xxx-res/android_common/gen/android/R.srcjar -o out_sys/soong/.intermediates/vendor/xxx/proprietary/framework/base/core/res/xxx-res/android_common/extra_packages --prefix '--extra-packages '
error: invalid package ID 0x0a. Must be in the range 0x7f-0xff..
15:27:28 ninja failed with: exit status 1
原因: Android.bp设置的--package-id 有问题,
解决方法:加上--allow-reserved-package-id即可
aapt 是Android Asset Packaging Tool的缩写,是编译和打包资源的工具。而aapt2是在aapt上做了优化。
Android Gradle Plugin 3.0.0或者更高版本默认开启aapt2。当然也可以在配置文件中手动关闭aapt2。在gradle.properties设置android.enableAapt2=false即可
aapt2将原先的资源编译打包过程拆分成了两部分,即编译和链接。
编译:将资源文件编译为二进制格式文件
链接:将编译后的所有文件合并,打包成一个单独文件
这种方式可以很好的提升资源的编译性能,比如只有一个资源文件发生改变时,你只需要重新编译改变的文件,然后将其与其他未改变的资源进行链接即可。而之前的aapt是将所有资源进行merge,merge完后将所有资源进行编译,产生一个资源ap_文件,该文件是一个压缩包,这样带来的后果就是即使只改变了一个资源文件,也要进行全量编译。
编译
aapt2支持编译所有的资源文件,并产生.flat格式的文件。
Input output
res/values/目录下的xml文件 *.asrc.flat 格式的文件
其他资源文件 除 res/values/ 目录下的XML文件外,都是 *.flat格式文件. 此外所有的 PNG 文件默认压缩为 *.png.flat文件. 可以使用 --no-crunch 参数禁止压缩PNG图片
编译语法
aapt2 compile path-to-input-files [options] -o output-directory/
1
Compile 命令行参数
Option Description
-o path 指定输出文件路径,若是不设置--dir directory,只是传了单个文件的path(path的需要严格按照这个格式path/resource-type[-config]/file存放,否则编译时会提示“bad resource path”),那么-o 后面的path设置为目录,若是设置--dir,则不必要再传入单个文件的path,同时-o后面的path应设置为文件名,比如:res.zip之类
--dir directory 指定扫描的资源目录
--no-crunch 禁止PNG图片压缩处理
-v 打开详细日志
举例
1)编译单个xml文件
aapt2 compile -v res/values/strings.xml -o out/
2)编译整个资源目录res
aapt2 compile -v --dir res -o res.zip
链接
在链接阶段,aapt2首先合并编译阶段生成的文件,像二进制XML文件,处理后的PNG文件等,然后,将其打包成一个apk文件。此外,在此阶段可以生成其他辅助文件,如R.java和ProGuard规则文件。当然,此时生成的apk文件并不包含dex文件,也没有签名。
链接语法
aapt2 link path-to-input-files [options] -o outputdirectory/outputfilename.apk --manifest AndroidManifest.xml
1
常用link命令行参数
Option Description
-o path 指定输出文件路径
--manifest file 指定AndroidManifest文件路径
-I path 指定android.jar路径
-- emit-ids path 产生资源id映射文件名,可以适用于–stable-ids
--stable-ids 使用–emit-ids生成的文件,包含资源类型名称列表及其分配的ID。
--package-id package-id 指定生成资源索引表的packageID ,设置的packageID 必须大于或者等于0x7f。要是与 --allow-reserved-package-id联合使用就可以不受这个限制
--allow-reserved-package-id 允许设置packageId为 0x02 到 0x7e ,这个只适用最小版本是26及以下(注意:这个在buildToolVersion:28.0.3之后才有的)
--java directory 指定生成R.java的目录
-A directory 指定需要打包进apk的assets目录
-v 打开详细日志
举例
1)生成R.java放到build目录,生成资源id映射文件输出到当前目录ids.txt,同时设置packageID为0x50,res.zip为上一步编译得到的.flat压缩包
aapt2 link -I D:/Android/Sdk/platforms/android-27/android.jar --allow-reserved-package-id --package-id 0x50 --java build --emit-ids ids.txt -o res.apk --manifest AndroidManifest.xml res.zip
1
注意事项
要在AS 3.0 gradle中更好使用aapt2支持,请设置项目build.gradle的classpath为:
classpath 'com.android.tools.build:gradle:3.2.1'
1
同时,gradle/gradle-wrapper.properties文件的distributionUrl设置为:
https\://services.gradle.org/distributions/gradle-4.8-all.zip
1
那么,也就可以在app的build.gradle设置aaptOptions:
aaptOptions {
additionalParameters "--allow-reserved-package-id", "--package-id"," 0x50"
}
在进行插件化开发时,如果插件apk含有res资源,宿主apk和插件apk在编译时都会产生自己的resources.arsc。由于打包后的宿主和插件apk资源id默认都是0x7f开头,那么它们的resources.arsc中的资源id必定是有相同的情况,会引起资源id冲突问题。
解决问题目前一共有两种思路:
1. 修改aapt源码,定制aapt工具,编译期间修改PP段。(PP字段是资源id的第一个字节,表示包空间)
DynamicAPK的做法就是如此,定制aapt,替换google的原始aapt,在编译的时候可以传入参数修改PP段:例如传入0x05编译得到的资源的PP段就是0x05。对于具体实现可以参考这篇博客https://blog.youkuaiyun.com/jiangwei0910410003/article/details/50820219
2. 修改aapt的产物,即,编译后期重新整理插件Apk的资源,编排ID。
VirtualApk采用的就是这个方案。对于具体实现可以参考这篇博客https://blog.youkuaiyun.com/weixin_43887839/article/details/86651232
这两种方式都有点麻烦,这两天忽然发现了aapt2支持一些新参数,其中有两个参数可以直接指定编译出apk的id范围:
–package-id package-id 指定生成资源索引表的packageID ,设置的packageID 必须大于或者等于0x7f。要是与 --allow-reserved-package-id联合使用就可以不受这个限制
–allow-reserved-package-id 允许设置packageId为 0x02 到 0x7e ,这个只适用最小版本是26及以下(注意:这个在buildToolVersion:28.0.3之后才有的)
例如在AS的app模块gradle文件中android括号内加上如下配置:
aaptOptions {
additionalParameters '--allow-reserved-package-id','--package-id','0x70'
}
同时注意aapt2是开启状态,这样编译出来的apk resourceId就是0x70开头的了,与默认的0x7f区分开来。
aapt2 compile资源(编译res目录下的资源)
--dir 编译的目录
-o 编译生成的压缩包
--legacy 将使用早期版本的 AAPT 时允许的错误视为警告
aapt2 compile -o outRes.zip --dir res --legacy
aapt2 compile (目标资源文件编译) 编译出对应flat文件
aapt2 compile res/values/string.xml -o compiled/
aapt2 link
aapt2 link (res,assets,AndroidManifest.xml资源,R文件生成)出apk包
--auto-add-overlay 允许在叠加层中添加新资源,而不使用 标记
-0 mp4 不想压缩mp4文件
-R file 如果您提供与现有文件重叠(扩展或修改现有文件)的资源文件,系统会使用最后提供的冲突资源
--java directory 指定要在其中生成 R.java 的目录。
-I 提供平台的 android.jar 或其他 APK(如 framework-res.apk)的路径,这在构建功能时可能很有用。
如果您要在资源文件中使用带有 android 命名空间(例如 android:id)的属性,则必须使用此标记
aapt2 link -o outputfilename.apk res1.zip -R res2.zip -A assets -I android.jar -I constraint-layout-1.0.2.aar --manifest AndroidManifest.xml --auto-add-overlay -0 mp4 --java rdir
https://blog.youkuaiyun.com/jiang877864109/article/details/117470972