V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Moyudawang
V2EX  ›  Android

Android 项目多个 Jar 包有命名空间冲突,有办法解决吗?

  •  
  •   Moyudawang · 2021-04-21 09:23:17 +08:00 · 11015 次点击
    这是一个创建于 1337 天前的主题,其中的信息可能已经有所发展或是发生改变。

    简单来说,同一个芯片的 SDK 被两个硬件组装厂家做了封装,我们的项目添加两个 Module 分别引用两个厂家封装后的 SDK(jar 、so),然后他们引用的芯片 SDK 就出现命名空间冲突了,而且他们用的芯片 SDK 版本还不一样,让厂家修改也不现实。
    现在就一直报错几个 Module 引用的 Jar 文件中有相同的内容,
    尝试把 Module 编译成 dex 动态加载,可是 dex 不能把 jar 和 so 打包进去,
    有没有大佬遇到过这种问题?望赐教

    38 条回复    2021-04-22 11:59:39 +08:00
    HongJay
        1
    HongJay  
       2021-04-21 09:26:31 +08:00
    jar 不能编辑么。gradle 不是有排除语法么
    Moyudawang
        2
    Moyudawang  
    OP
       2021-04-21 09:27:53 +08:00
    @HongJay 厂家的 SDK,不能编辑,因为用的版本不同,也不能排除
    xne110
        3
    xne110  
       2021-04-21 09:30:25 +08:00
    如果就是个 Jar 的话,我倒是遇到过,我是直接用 zip 打开 Jar 把里面重复的东西直接删了 ,在导入就 ok 了
    Moyudawang
        4
    Moyudawang  
    OP
       2021-04-21 09:33:28 +08:00
    @xne110 是硬件厂家引用了芯片厂家的 so 和 Jar,我们再引用硬件厂家的 Jar
    Moyudawang
        5
    Moyudawang  
    OP
       2021-04-21 09:34:28 +08:00
    @xne110 而且他们用的芯片 Sdk 版本也不一样,直接删除不行
    wsxyeah
        6
    wsxyeah  
       2021-04-21 09:36:42 +08:00 via iPhone
    改 bytecode,参考下 Android X 的做法
    cache
        7
    cache  
       2021-04-21 09:41:13 +08:00
    我记得有个工具专门干这个事
    好像叫 jarjar
    xne110
        8
    xne110  
       2021-04-21 09:44:11 +08:00
    就是有两三方包里引用了 同一个不同版本的三方包 两个直接删了,在自己项目里引用那个相同三方包 不就好了,如果他们混淆了 那就没办法了 ,我可能想的比较简单哈
    Moyudawang
        9
    Moyudawang  
    OP
       2021-04-21 09:52:19 +08:00
    @wsxyeah 看一眼头大,慢慢研究一下
    @cache 我去试试
    @xne110 不同版本不一定向下兼容,命名一样,实现不一定一样
    actar
        10
    actar  
       2021-04-21 10:01:16 +08:00
    你们是多种设备吗,每种设备使用不同的 SDK 。如果是这样的话,可以考虑多维度打包。每种设备只打入自己需要的包。关键字:flavorDimensions,productFlavors 。这样每种设备打出来的包是不一样的。缺点就是每一种设备都会打一个包,后续更新会需要维护多种设备的安装包。但是打包的时候会将多种设备的安装包同时打出来,不需要一个一个的打包。
    Moyudawang
        11
    Moyudawang  
    OP
       2021-04-21 10:04:52 +08:00
    @actar 是的,适配多种设备,现用的也是这种办法,不过还是想只打包到一个 App 里,这样发布到商店也简单点
    wms
        12
    wms  
       2021-04-21 10:05:56 +08:00
    把两个 SDK 用到的部分做成两个独立的服务, 主 APP 去跟这个两个服务通信
    Moyudawang
        13
    Moyudawang  
    OP
       2021-04-21 10:14:03 +08:00
    @wms 那这两个服务不也是 App 启动的吗?现在编译通不过
    wms
        14
    wms  
       2021-04-21 10:18:32 +08:00
    @Moyudawang 每个服务做一个 APK, 将三个 APK 打包成一个
    timethinker
        15
    timethinker  
       2021-04-21 10:25:37 +08:00
    自己实现一个类加载器,加载不同 SDK 的 jar 可行性如何?
    就是说把厂商 SDK 的 jar 当做文件资源,不直接通过 gradle 打包,而是使用动态加载的方式载入需要的依赖。
    lawfun
        16
    lawfun  
       2021-04-21 10:39:00 +08:00
    我觉得 @qwe520liao 说的可行。

    原文中的
    “尝试把 Module 编译成 dex 动态加载,可是 dex 不能把 jar 和 so 打包进去”
    可以把 so 都打进 主 APP 里。

    破解 jar 看源码,分析代码自己再实现下应该也行,不过可能会很费时。
    Moyudawang
        17
    Moyudawang  
    OP
       2021-04-21 10:50:30 +08:00
    @wms 我还没试过这种,可以尝试一下
    @qwe520liao android 不能动态加载 jar 吧,只能先编译成 dex,第三方的 jar 我试了,编译成 dex 失败
    @lawfun 这个确实太费时了,因为厂家的 jar 包不止包含芯片的功能,还有厂家其他硬件的功能
    Moyudawang
        18
    Moyudawang  
    OP
       2021-04-21 11:04:22 +08:00
    @cache 试了不行,Jar 里含有 Jni 方式加载 So 里的方法,所以命名空间不能改,
    mmrx
        19
    mmrx  
       2021-04-21 11:53:14 +08:00
    @Moyudawang #14 的方案感觉可行,俩库的 apk 当做服务,用哪个装哪个 apk,然后用 AIDL 通信
    Moyudawang
        20
    Moyudawang  
    OP
       2021-04-21 12:29:32 +08:00
    @mmrx 嗯,这个方式我需要花时间尝试一下
    kingiis
        21
    kingiis  
       2021-04-21 13:15:15 +08:00
    看你说涉及到了 so 文件
    只能从源码层面 二次开发重新导出
    ParfoisMeng
        22
    ParfoisMeng  
       2021-04-21 13:51:13 +08:00   ❤️ 1
    为啥让厂家修改不现实……
    p2pCoder
        23
    p2pCoder  
       2021-04-21 14:03:09 +08:00
    maven 有 maven-shade,gradle 应该也有类似的工具
    Moyudawang
        24
    Moyudawang  
    OP
       2021-04-21 14:14:00 +08:00
    @kingiis 没有源码,也没有这个能力
    @ParfoisMeng 因为让他们改过,有的改过也不行,有的说改不了,例如设备上的扫描头模块,很多组装厂家用的是一样的模块,但是为了连接他们的硬件又把扫描头的 sdk 封装了一层,要改大家全都一起改,太难了
    @p2pCoder 这还真不知道
    Moyudawang
        25
    Moyudawang  
    OP
       2021-04-21 14:17:55 +08:00
    @ParfoisMeng 也怪我们采购了太多种类的设备,厂家提供的 sdk 都是大一统集成在一起的(RFID 、NFC 、条码扫描头),用起来是方便,冲突了就麻烦了
    xFrye
        26
    xFrye  
       2021-04-21 14:24:00 +08:00
    没有包名检测的话,用 jarjar 就好,之前接一个第三方库也有个冲突的,给他命名空间改了
    Moyudawang
        27
    Moyudawang  
    OP
       2021-04-21 14:47:21 +08:00
    @xFrye 有些方法是用 JNI 调用的,包名不能改
    2bab
        28
    2bab  
       2021-04-21 14:53:42 +08:00
    1. 编译期解决的话,改命名空间最快
    2. 运行期解决的话,我依旧推荐动态加载 + 区分 Classloader,打不出 Dex 多半只是姿势问题,懒得研究的话,你可以直接建一个全空的 Android 工程,就引用这个 SDK,然后打了 APK 再把 Dex 给解压出来
    Moyudawang
        29
    Moyudawang  
    OP
       2021-04-21 15:34:29 +08:00
    @2bab 嗯,我也觉得动态加载才是根本解决办法,我再研究研究 dex,多谢提醒
    ParfoisMeng
        30
    ParfoisMeng  
       2021-04-21 17:47:30 +08:00
    @Moyudawang 如果是版本不统一属实难搞,可以和每个厂家约定统一使用最新稳定版本。然后都打 without 包( compileOnly )出来,你自己去依赖指定版本。
    littlewing
        32
    littlewing  
       2021-04-21 21:20:00 +08:00
    @xne110 并不是,而是两个同名的包是不同功能,而且两个都需要用到
    limbo0
        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 完后引入你的项目, 互不影响
    Moyudawang
        34
    Moyudawang  
    OP
       2021-04-22 08:09:18 +08:00
    @ParfoisMeng 有的设备都是几年前的了,厂家懒得搞

    @humpy 感谢指点
    @limbo0 谢谢 我会去试试
    lqw3030
        35
    lqw3030  
       2021-04-22 09:25:52 +08:00 via iPhone
    独立类加载器加载
    Aviciii
        36
    Aviciii  
       2021-04-22 09:55:39 +08:00
    我遇到过项目需要引用不同版本的 jar 包,最后用的 jarjar.jar 改的包名,然后把相关引用也改掉。不知道对你有没有帮助。
    gam2046
        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 中,可以方便调用。
    Wounmay9976
        38
    Wounmay9976  
       2021-04-22 11:59:39 +08:00 via Android
    感觉#14 是开发最优,要是能接受这样最简单快捷。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3350 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 11:22 · PVG 19:22 · LAX 03:22 · JFK 06:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.