简单来说,同一个芯片的 SDK 被两个硬件组装厂家做了封装,我们的项目添加两个 Module 分别引用两个厂家封装后的 SDK(jar 、so),然后他们引用的芯片 SDK 就出现命名空间冲突了,而且他们用的芯片 SDK 版本还不一样,让厂家修改也不现实。
现在就一直报错几个 Module 引用的 Jar 文件中有相同的内容,
尝试把 Module 编译成 dex 动态加载,可是 dex 不能把 jar 和 so 打包进去,
有没有大佬遇到过这种问题?望赐教
1
HongJay 2021-04-21 09:26:31 +08:00
jar 不能编辑么。gradle 不是有排除语法么
|
2
Moyudawang OP @HongJay 厂家的 SDK,不能编辑,因为用的版本不同,也不能排除
|
3
xne110 2021-04-21 09:30:25 +08:00
如果就是个 Jar 的话,我倒是遇到过,我是直接用 zip 打开 Jar 把里面重复的东西直接删了 ,在导入就 ok 了
|
4
Moyudawang OP @xne110 是硬件厂家引用了芯片厂家的 so 和 Jar,我们再引用硬件厂家的 Jar
|
5
Moyudawang OP @xne110 而且他们用的芯片 Sdk 版本也不一样,直接删除不行
|
6
wsxyeah 2021-04-21 09:36:42 +08:00 via iPhone
改 bytecode,参考下 Android X 的做法
|
7
cache 2021-04-21 09:41:13 +08:00
我记得有个工具专门干这个事
好像叫 jarjar |
8
xne110 2021-04-21 09:44:11 +08:00
就是有两三方包里引用了 同一个不同版本的三方包 两个直接删了,在自己项目里引用那个相同三方包 不就好了,如果他们混淆了 那就没办法了 ,我可能想的比较简单哈
|
9
Moyudawang OP |
10
actar 2021-04-21 10:01:16 +08:00
你们是多种设备吗,每种设备使用不同的 SDK 。如果是这样的话,可以考虑多维度打包。每种设备只打入自己需要的包。关键字:flavorDimensions,productFlavors 。这样每种设备打出来的包是不一样的。缺点就是每一种设备都会打一个包,后续更新会需要维护多种设备的安装包。但是打包的时候会将多种设备的安装包同时打出来,不需要一个一个的打包。
|
11
Moyudawang OP @actar 是的,适配多种设备,现用的也是这种办法,不过还是想只打包到一个 App 里,这样发布到商店也简单点
|
12
wms 2021-04-21 10:05:56 +08:00
把两个 SDK 用到的部分做成两个独立的服务, 主 APP 去跟这个两个服务通信
|
13
Moyudawang OP @wms 那这两个服务不也是 App 启动的吗?现在编译通不过
|
14
wms 2021-04-21 10:18:32 +08:00
@Moyudawang 每个服务做一个 APK, 将三个 APK 打包成一个
|
15
timethinker 2021-04-21 10:25:37 +08:00
自己实现一个类加载器,加载不同 SDK 的 jar 可行性如何?
就是说把厂商 SDK 的 jar 当做文件资源,不直接通过 gradle 打包,而是使用动态加载的方式载入需要的依赖。 |
16
lawfun 2021-04-21 10:39:00 +08:00
我觉得 @qwe520liao 说的可行。
原文中的 “尝试把 Module 编译成 dex 动态加载,可是 dex 不能把 jar 和 so 打包进去” 可以把 so 都打进 主 APP 里。 破解 jar 看源码,分析代码自己再实现下应该也行,不过可能会很费时。 |
17
Moyudawang OP @wms 我还没试过这种,可以尝试一下
@qwe520liao android 不能动态加载 jar 吧,只能先编译成 dex,第三方的 jar 我试了,编译成 dex 失败 @lawfun 这个确实太费时了,因为厂家的 jar 包不止包含芯片的功能,还有厂家其他硬件的功能 |
18
Moyudawang OP @cache 试了不行,Jar 里含有 Jni 方式加载 So 里的方法,所以命名空间不能改,
|
19
mmrx 2021-04-21 11:53:14 +08:00
@Moyudawang #14 的方案感觉可行,俩库的 apk 当做服务,用哪个装哪个 apk,然后用 AIDL 通信
|
20
Moyudawang OP @mmrx 嗯,这个方式我需要花时间尝试一下
|
21
kingiis 2021-04-21 13:15:15 +08:00
看你说涉及到了 so 文件
只能从源码层面 二次开发重新导出 |
22
ParfoisMeng 2021-04-21 13:51:13 +08:00 1
为啥让厂家修改不现实……
|
23
p2pCoder 2021-04-21 14:03:09 +08:00
maven 有 maven-shade,gradle 应该也有类似的工具
|
24
Moyudawang OP @kingiis 没有源码,也没有这个能力
@ParfoisMeng 因为让他们改过,有的改过也不行,有的说改不了,例如设备上的扫描头模块,很多组装厂家用的是一样的模块,但是为了连接他们的硬件又把扫描头的 sdk 封装了一层,要改大家全都一起改,太难了 @p2pCoder 这还真不知道 |
25
Moyudawang OP @ParfoisMeng 也怪我们采购了太多种类的设备,厂家提供的 sdk 都是大一统集成在一起的(RFID 、NFC 、条码扫描头),用起来是方便,冲突了就麻烦了
|
26
xFrye 2021-04-21 14:24:00 +08:00
没有包名检测的话,用 jarjar 就好,之前接一个第三方库也有个冲突的,给他命名空间改了
|
27
Moyudawang OP @xFrye 有些方法是用 JNI 调用的,包名不能改
|
28
2bab 2021-04-21 14:53:42 +08:00
1. 编译期解决的话,改命名空间最快
2. 运行期解决的话,我依旧推荐动态加载 + 区分 Classloader,打不出 Dex 多半只是姿势问题,懒得研究的话,你可以直接建一个全空的 Android 工程,就引用这个 SDK,然后打了 APK 再把 Dex 给解压出来 |
29
Moyudawang OP @2bab 嗯,我也觉得动态加载才是根本解决办法,我再研究研究 dex,多谢提醒
|
30
ParfoisMeng 2021-04-21 17:47:30 +08:00
@Moyudawang 如果是版本不统一属实难搞,可以和每个厂家约定统一使用最新稳定版本。然后都打 without 包( compileOnly )出来,你自己去依赖指定版本。
|
31
humpy 2021-04-21 17:56:08 +08:00
maven 可以用 maven-shade-plugin
示例: https://maven.apache.org/plugins/maven-shade-plugin/examples/class-relocation.html gradle 可以用 shadow plugin 地址: https://plugins.gradle.org/plugin/com.github.johnrengelman.shadow 示例: https://imperceptiblethoughts.com/shadow/configuration/relocation/ |
32
littlewing 2021-04-21 21:20:00 +08:00
@xne110 并不是,而是两个同名的包是不同功能,而且两个都需要用到
|
33
limbo0 2021-04-22 01:13:04 +08:00
maven-shade 正解, 把 A 厂家的包 shade 成 a.com.x.x , B 厂家的包 shade 成 b.com.x.x, build 完后引入你的项目, 互不影响
|
34
Moyudawang OP |
35
lqw3030 2021-04-22 09:25:52 +08:00 via iPhone
独立类加载器加载
|
36
Aviciii 2021-04-22 09:55:39 +08:00
我遇到过项目需要引用不同版本的 jar 包,最后用的 jarjar.jar 改的包名,然后把相关引用也改掉。不知道对你有没有帮助。
|
37
gam2046 2021-04-22 11:09:00 +08:00
假设 a.jar 包含 com.sample.MyClass,b.jar 包含 com.sample.MyClass,
a 与 b 的功能完全不同,则可以考虑在编译时,不引入 a.jar 与 b.jar 在使用期间(运行期间)通过不同的 ClassLoader 分别加载 a 与 b 即可 对应到 Android 即 BaseDexClassLoader 。 缺点是需要通过反射调用 a 与 b 的方法,当然如果他们有共同实现的接口或共同的父类,可以把这个这个接口或类放到主 jar 中,可以方便调用。 |
38
Wounmay9976 2021-04-22 11:59:39 +08:00 via Android
感觉#14 是开发最优,要是能接受这样最简单快捷。
|