• 八月
  • 18
  • load

通过dex分包,解决aar冲突问题 2020-08-18 22:01:23

故事开始:

一天,项目需求需要同时接入两个aar包,分别是baidusdk.aar,tencent.aar,然后调用他们Play().start()即可完成工作,不过是工作中很普通的事件

然而,由于厂商的aar引入了相同的东西,打破了这份宁静

Duplicate class com.sqsxblog.sdk.Backup found in modules jetified-baidusdk-runtime.jar (:baidusdk:) and jetified-tencentsdk-runtime.jar (:tencentsdk:)

Duplicate class com.sqsxblog.sdk.Backup$Companion found in modules jetified-baidusdk-runtime.jar (:baidusdk:) and jetified-tencentsdk-runtime.jar (:tencentsdk:)

很显然,这俩aar同时引入了com.sqsxblog.sdk.Backup,导致冲突了,理论上来讲,只要随便删除一个依赖就能解决这个问题

没有效果,直接打开aar的jar文件才发现,这玩意是直接镶在里面的,那我直接删掉就行了吧?

以防万一,直接反编译一看发现,他们包名冲突也算了,写的东西还不一样


baidusdk的com.sqsxblog.sdk.Backup

tencent的com.sqsxblog.sdk.Backup

看来这俩是必须要共存的,想来想去就一个办法,动态加载aar?显然不行,aar里面的东西还是一个jar,android跑的是dex。

看来,要靠动态加载dex了。

先动态加载baidusdk。步骤的话,先通过File->New module,选择Android Library,module name我就叫dexbaidusdk好了,package name我就填com.sqsxblog.dexbaidu

在app的gradle下添加 classpath 'com.kezong:fat-aar:1.2.15'

在dexbaidusdk的gradle顶部添加 apply plugin: 'com.kezong.fat-aar'

然后吧,这样引入aar文件 embed (name:'baidusdk',ext:'aar')

在这里可能就产生疑问了,我就是想引入个aar,为啥还要这么麻烦?

因为你也要编译一个aar出来,如果直接implementation,那么你引入的aar是不会编译进去的。

创建一个interface,我就在com.sqsxblog里创建一个BaiduSDKInf好了,你需要调哪个方法就声明哪个,我目的是调用start(),那么就这么声明一个start的抽象方法

然后再创建一个BaiduSDK,实现这个BaiduSDKInf

目录如图

点击右侧gradle,dexbaidu->tasks->other->assembleRelease,双击执行

在dexbaidu->build->outputs->aar目录下,得到dexbaidu-release.aar

解压里面的classes.jar,移动到/android sdk目录/build-tools/x.x.x/

打开命令行,输入./dx --dex --output classes.dex classes.jar,得到classes.dex

改名为baidusdk.dex,复制到assets目录下。

把dexbaidu module创建的BaiduSDKInf复制过来,由于我们创建的包名是com.sqsxblog,所以项目也要创建这个包名(app包名是com.sqsxblog.app,因此我直接放在com/sqsxblog目录即可)

在MainActivity声明两个函数

调用方法

tencentSDK方法相同,创建module,编译出dex引入

点击看看

到这里,通过dex分包的方式,成功解决了包名冲突的问题。不过也产生了第二个问题了。

如果so文件也冲突怎么办?

把你需要的so文件也放进assets里,复制到你希望的目录下,然后改造我们刚刚声明的loadDexClass函数。

其实它返回的是DexClassLoader,它第三个参数传的是null,改成你复制的目录即可。

假设你把so复制到/sdcard里,那这参数就写/sdcard就行。


说真,我也觉得这些操作很麻烦,就当是练习如何使用分包。

正在加载评论...

0 / 240

警告

确定