记录 SDK 对外输出时碰到的两个问题

摘要:compile provided 的运用,不同 moudule 之间依赖本地库和远程库的区别.

记录一下最近对接 SDK 碰到的一些问题,后面再次碰到时能够快速结局。

问题一 关于compile、provided

背景:由于 SO 冲突的原因,我们对外提供的 SDK 现在需要从原来的 aar 形式改为 Jar + SO 的形式,假设我们统一对外提供的 SDK 叫 A.aar, A 在内部会依赖 SDK B.aar 和 So 库。

先复习一下 aar 和 jar 的压缩文件结构:

  • aar 结构

res 中放置的是资源文件
libs 中放置的是 jar
jni 中放置的是 so

  • jar 结构

里面就是 Library 的包结构以及类的 CLASS 文件。

一开始我把 SDK B 打包成 B.jar,然后在 SDK A 中依赖 B.jar ,然后在打 jar 包的时候将 B 一起给打进 A.jar 中(如何在打 jar 包时将 libs 下的 jar 一并打入: Android Studio 中打 jar 包和 aar 包姿势总结),然后对外提供新的 A.jar + SO ,但是使用方在编译时报出如下错误:

重点: android.view.inflateexception binary xml file line #0 error inflating class ...

在 inflate XML 文件的时候出错了,到这里,我立马就想到,是不是 SDK A 或者 B 中有用到一些资源文件,而 Jar 包并不能包含资源文件所导致的?

回去检查后发现,SDK B 中确实依赖有一个 XML 文件,但是 jar 中是没有包含的,所以在运行时会报出错误。

这么说,直接将 B 的 jar 给 打进 A 的 jar 中这种方法因为资源文件的问题,是不可行的了,所以又想到一个方法:

A SDK 还是依赖 B SDK 的 aar,然后在编译阶段是可以通过的,并且在最后打 jar 包时,是没办法将 B.aar 给打进总的 jar 中的,所以就额外提供 B.aar,最后对外输出是 A.jar + B.aar + so。

其中 A 的 gradle 文件如下:

这样使用方在使用的时候就正常了, 但是在混淆后打 APK 包时,又出现了一个错误:

重点: Duplicate zip entry [com/xxx/xxx/R$anim.class))

通过包名可以确定 com/xxx/xxx/R$anim.class 是 B SDK 中的类。

问题很清楚了,是因为 B SDK 引用了两次,在打包时反射调用动画的 id 时报出来的错误,所以将 A.jar 重复依赖的 B.aar 给删除掉就行了。但是检查了一遍又一遍发现,B.aar 并没有被依赖多次。

但是从逻辑上来说,A.jar 依赖了 B.aar ,然后又额外提供了 B.aar ,只有这个地方是存在逻辑上的重复依赖的,但是并没有真的重复依赖。

注意上图中 compile(name:'B',ext:'aar') 其中 compile 的含义:对所有 buildType 以及 flavors 进行编译并打包到 apk。

到这里就基本清楚了, 我们在 A 中依赖的 B.aar 只是为了让编译通过,并不需要这里的 B 的相关数据给打包打 APK 中,需要打包到 APK 中的应该是额外提供的 B.aar。

所以将 comile 给换成 provided ,其作用是:只在编译时使用,只参与编译,不打包到最终 apk 。

这么一来,成功解决如上问题。

问题二 moudle 间本地和远程包依赖

假设主 moudleA 依赖子 moudleB ,在 moudle B 中会依赖远程的库 pp-sdk:

1
2
compile 'com.aaa.bbb:pp-sdk:1.0.14'

moudle A B 之间的依赖关系:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#A的build.gradle文件
android {
.....
repositories {
flatDir {
dirs 'libs'
}
}
}
dependencies {
compile project(':B')
}

这种依赖方式编译和运行都是没问题的,但是如果 B moudle 依赖的 pp-sdk 由远程仓库的变成本地的 aar:

1
2
complie(name:'pp-sdk-v1.0.14',ext:'aar')

那么就会报错:

原因是 moudle A 用到了 pp-sdk 中的类,但是 moudle A 在它自己的 libs 文件夹下找不到这个类的地址,所以应该让 moudle A 也能找到 moudle B 中的 libs 路径,也就是说,如果有一个全局的地方,能够让 moudle A 设置一下 moudle B 的 libs 地址,那就可以了。

根目录下的 build.gradle 刚好就可以提供这样的功能:

1
2
3
4
5
6
7
8
9
10
allprojects {
repositories {
jcenter()
//添加如下代码
flatDir{
dirs project(':B').file('libs')
}
}
}

allprojects 这个方法下的配置是应用到所有的 moudle 中的,所以在这里将 moudle B 的 libs 地址给添加进来,moudle A 就能找到 moudle B 中 libs 目录下的 pp-sdk 了。

共82.3k字
0%
.gt-container a{border-bottom: none;}