Android SDK开发嵌套aar文件

关于Android SDK开发中嵌套aar文件的一些问题

关于这个问题的背景:业务需要给外部提供一个sdk,以aar文件的形式提供到对方,但是在sdk也无需求中需要用到另外的第三方服务aar文件,所以过程中就存在了aar文件嵌套aar文件的问题。

除去上述问题,在整个sdk开发过程中还踩到了许多坑,下文一一列出,总结归纳。

开发过程中需要自己写一个壳进行调试sdk,最开始通过sdk的依赖使用一个module形式的引用,开发过程中毫无问题,也方便调试。

但是我们最终提供出去的sdk文件肯定不能是一个完整的module目录,所以在开发过程完成以后最终要将module编译成aar文件再放置到壳中进行一遍流程测试。

资源文件冲突

这里记录碰到的第一个问题,资源文件名冲突导致的问题,轻则显示混乱,重则程序crash,库文件中存在相同名字的资源文件,module中使用到的资源文件会变成主项目下的资源文件。

java.lang.NoSuchFieldError: No static field jni_libb_tv of type I in class Lcom/demo/jnilibb/R$id; or its superclasses (declaration of 'com.demo.jnilibb.R$id' appears in /data/app/com.demo.sdkhost-37V1XNuiAYSy3X3DBvdsgQ==/base.apk)

这是我的一个crash,由于主项目和我的module目录下都有一个MainAcitivty和activity_main的layout布局,在module中的MainActivity调用findViewById发生了crash,主要就是因为这里的activity_main用成了host目录下的layout文件。针对这个问题的解决方式就是规范化命名方式,以module名为前缀,避免资源冲突。这个在阿里的Android代码规范中也有提及,最近流行的组件化module命名规范大多也遵循这个规范。

下面是官方文档对资源文件冲突的介绍:

构建工具会将库模块中的资源与相关应用模块的资源合并。如果在两个模块中均定义了给定资源 ID,将使用应用中的资源。

如果多个 AAR 库之间发生冲突,将使用依赖项列表首先列出(位于 dependencies 块顶部)的库中的资源。

为了避免常用资源 ID 的资源冲突,请使用在模块(或在所有项目模块)中具有唯一性的前缀或其他一致的命名方案。

可以看到,优先级是应用>库,库之间根据在build文件定义的顺序确认优先级。

build构建版本

这个是我在写这篇总结的时候碰到的问题,我本想自己写一个demo,然后把问题都记录下来,却在打包的时候碰到了问题,既然碰到了就顺手记录下来。

java.lang.NoClassDefFoundError: Failed resolution of: Lcom/demo/jnilibrarya/MainActivity;

场景如下:我在module中设置一个点击事件,跳到嵌套aar文件中的一个activity,然后发生了NoClassDefFoundError异常。对于这个问题,我们可以看一下当前aar文件的一个结构,分析一下:

Android SDK开发嵌套aar文件_第1张图片

这里classes.jar 文件中包裹了另一个classes.jar 文件,点开被包裹的classes.jar文件可以看到另一个aar文件中的java代码,而我们module本身的代码却在外层classes.jar文件里面,这个应该就是原因了。

经过一番测试,发现这个问题主要和当前build构建工具版本有关,碰到这个问题的时候用的是3.4.2版本构建工具,但是如果我切到3.1.2版本打出来的aar文件结构却如下:

Android SDK开发嵌套aar文件_第2张图片可以看到只有一个classes.jar文件,两个aar文件的java代码都在同一个classes.jar文件中,调用aar类文件也不会有错误,但是这里的清单文件整合并没有自己去做,这就导致内部aar文件的activity无法被调用,因为没有注册。如果需要做的话建议自己写gradle去进行整合,将子aar文件的清单文件整合到当前module的清单文件。

对于这个问题的一个主要原因已经很明显了,gradle编译不同版本对于aar文件打包的逻辑有不同,所以在这里注定会遇到很多坑,特别是自己切入打包流程写gradle插件的时候,可能会碰到很多兼容性问题。要保持一颗平常心对待。

so文件问题

关于so文件也会有上面java文件的问题,下面这个图是我们不处理的情况下的aar文件的格式:

Android SDK开发嵌套aar文件_第3张图片

可以看到,这里也存在两个jni文件夹,一个在最外层,一个在classes.jar文件内部,最外层中的是module中自己的so文件所在位置,而子aar文件的so文件会存放在classes.jar文件中,而这个时候去掉用so中的方法的话就会报错,找不到相关so库。

处理方式:

手动解压子aar文件,将内部的so文件拷贝到module对应目录中,最终打出来包在外部jni文件就会包括子aar文件的so文件。

对于这种文件替换的方式可以通过gradle插件在打包前自动将对应的文件替换到对应目录底下。

你可能感兴趣的:(android)