- 八月
- 18
- load
- 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就行。
说真,我也觉得这些操作很麻烦,就当是练习如何使用分包。