热修复和插件化固定资源ID解决资源冲突的方案

2,779 阅读4分钟

1术语和缩略词

  • AAPT:Android Asset Packaging Tool,Android资源打包工具,将res文件夹所有的资源(layout\drawable\string\array等),asset下的资源,AndroidManifest.xml,Android.jar文件编译成为一个资源索引文件resource.arsc以及一个R.java类。asset下的资源不会编译,直接压缩进apk。
  • AAPT2:Android Studio3.0后默认为AAPT2打包方式,在AAPT基础上为资源的增量编译提供了支持,功能更加完善。
  • Gradle:是一款开源的自动化构建工具,使用灵活且性能极佳。

2背景

  • 在插件化过程中,原来项目需要用到插件的资源,涉及到加载插件的资源,因为插件是以apk的方式存在的,所以插件的ID和原来项目的ID可能导致重复,为了解决这个问题,需要把插件的资源ID重新排一遍,才给宿主加载和使用。
  • 过去使用Eclipse开发,使用的是aapt1的打包方案,在Eclipse中,publc.xml是aapt在打包资源时用来固定资源id的,如果资源在public.xml中有对应的id了,那么打包资源时就用已经有的id,因此只需要修改public.xml文件就可以完成固定资源ID。
  • 现在使用Android Studio开发,android gradle plugin 从1.3.0开始忽略了public.xml,因此我们需要换一种方式固定资源ID,避免和原来项目资源ID冲突。

3资源冲突方案

3.1 AAPT2参数修改法

  • aapt2支持一些新参数,其中有两个参数可以直接指定编译出apk的id范围:
命令内容
package-id指定生成资源索引表的packageID
allow-reserved-package-id最好设置packageId为 0x02 到 0x7f(实际测试中0x00-0xff全部可用) ,这个只适用最小版本是26及以下(注意:这个在buildToolVersion:28.0.3之后才有的)
  • 在app目录下的build.gradle中的android{}中添加以下内容,只能更改前四位

aaptOptions { additionalParameters '--allow-reserved-package-id','--package-id','0x10' }

  • 编译完成后进入以下目录查看R.java文件有没有修改到对应的ID,有则全部成功。注意:Android Studio4.2以上(4.0和4.1可能也存在)在项目中无法找到R.java文件,需要打开项目所在文件夹,手动搜索文件。

3.2 AAPT2标记法

在aapt2的链接阶段中,查看相关的链接选项:

命令内容
--emit-ids path在给定的路径下生成一个文件,该文件包含资源类型的名称及其 ID 映射的列表。它适合与 --stable-ids 搭配使用
--stable-idsoutputfilename.ext 使用通过 --emit-ids 生成的文件,该文件包含资源类型的名称以及为其分配的 ID 的列表。此选项可以让已分配的 ID 保持稳定,即使您在链接时删除了资源或添加了新资源也是如此
  • 根据上面的选项内容,我们可以利用--emit-ids和--stable-ids命令搭配可以实现id的固定。

第一步:

在app目录下的build.gradle中的android{}中添加以下内容

` aaptOptions {

    File publicTxtFile = project.rootProject.file('public.txt')
    //public文件存在,则应用,不存在则生成
    if (publicTxtFile.exists()) {
        project.logger.error "${publicTxtFile} exists, apply it."
        //aapt2添加--stable-ids参数应用
        aaptOptions.additionalParameters("--stable-ids", "${publicTxtFile}")
    } else {
        project.logger.error "${publicTxtFile} not exists, generate it."
        //aapt2添加--emit-ids参数生成
        aaptOptions.additionalParameters("--emit-ids", "${publicTxtFile}")
    }
}`

第二步:

  • 项目Clean一下,然后编译,查看项目目录下是否出现public.txt文件,如果没有出现则第一步的脚本放错地方,如果有就打开public.txt文件,打开后,一键替换需要替换的资源ID。

  • 注意:假如替换前4位则会报错,因为默认前四位只能是0x7f,因此最好只替换第5位,但这样的话同时只能存在15个插件,可以编写一个脚本将后5位改成由00001开始,每个资源ID加一的格式,对于一般的插件而言不会超过4位数,这样做的话第5和第6位都没有被占用,那么就可以同时存在最多240个插件。(假如想要修改前四位,可以添加方案一中的allow-reserved-package-id方法)

第三步:

  • 再次编译,通过--stable-ids和根目录下的public.txt进行资源id的固定,编译完成后进入以下目录查看R.java文件有没有修改到对应的ID,有则全部成功。
  • 注意:Android Studio4.2以上(4.0和4.1可能也存在)在项目中无法找到R.java文件,需要打开项目所在文件夹,手动搜索文件。

4总结

  • AAPT2参数修改法毫无疑问比AAPT2标记法更加简单,但缺点也很明显,只能修改资源ID的前四位,但是能够已经能够保证同时240个插件存在而不冲突,而AAPT2标记法也有缺点,就是编译的步骤多,而且编译有时候有问题,需要重新清理删除再编译。