为了账号安全,请及时绑定邮箱和手机立即绑定

接入sdk库的几点心得体会

标签:
Java

由于项目的特殊性,最近一直在往app工程里接入(更新)第三方sdk,并且app的一些基础控件也被其他项目组封装成了sdk来导入。在不停的sdk更新迭代过程中碰到了一些问题,记录一下为后续排查问题依据。

  • sdk本身内部可以依赖其他sdk库(假设为库A),此时库A不需要app显示导入,它在导入sdk时会自动导入进来(sdk发布时的aar文件有一个配对的pom.xml文件,他可以用来描述依赖),但可以通过exclude关键字取消对库A的自动导入。

  • 如果sdk本身依赖另一个库A,且app本身也对A库有导入依赖,这时就存在有两个地方对同一个库A的导入了。如果两处的版本号不一致的话,最终库A的什么版本是哪个呢?是以app的导入为准吗?还是以版本高的为准?结论是以版本号高的引用那个为准(打印依赖有向图可以看出)。
    问题:明明我只是升级了sdk的版本,但最终的依赖库A的版本怎么也变了?由于库A的内容变了,那调用库A的代码就有可能存在不一致性了,特别是涉及到大版本更新时。这是可以通过依赖关系图来查看依赖的变化点和变化来源在哪里。

  • 另外一种情况:还是以上面的结论为基础,假设app依赖的库A版本比较高(最终以这个高版本为准),且这个高版本库A相比sdk依赖的低版本刚好删掉某一个API接口(比如是大版本升级),而sdk内部又刚好有调用这个删掉了的接口。
    问题此时是app竟然可以编译过!!! 只是会等到在运行时抛出找不到方法的异常。这怎么办?很严重,很隐秘的问题。
    原因:针对这种情况刚开始还不能理解,都少了一个调用方法了为啥编译时没报错?后来想想也是正常的,这是因为app导入的sdk是以aar的形式引入的,而这个aar在sdk发布时就已经编译成字节码(class)了,所以此时编译app时编译器并不会再用javac去编译aar了(直接将aar的class类merge到app中),于是最终编译器没有检查调用关系的错误。
    验证:即使使用exclude将依赖库A排除依赖(最终的apk不包含库A的代码)也仍可以编译过。
    今天碰到了这种情况,一时无法理解:
    首先是一个sdk依赖的库A低版本(3.0.1)的接口:

//3.0.1public static Context build(Activity activity, boolean param1, boolean param2) {    //...}

然后是app依赖的库A高版本(3.0.3)的接口:

//3.0.3public static Context build(Context context, boolean param1, boolean param2) {    //...}

3.0.1版本与3.0.3版本的差异只是build()函数的第一个参数Activity变为了Context,但app升级了库A3.0.3版本后编译能通过,sdk内部却必现抛找不到方法异常:

java.lang.NoSuchMethodError: No static method build(Landroid/app/Activity;ZZ)Landroid/content/Context;

且我测试在app里调用这个build()方法又是正常的。为什么呢?原因就是上面说的(删掉了方法与修改了方法签名本质上是一样的),即使这里满足多态性(ContextActivity的基类)也不行。

  • 在编写sdk时,暴露的API类和接口不宜轻易改动,否则可能会出现上述的依赖问题。废弃的方法和类可以使用注解@Deprecated标识起来,需要改动的接口使用方法重载的方式增加接口,而不是去改动接口。

查看app的依赖关系的命令:

./gradlew :app:dependencies



作者:JarryWell
链接:https://www.jianshu.com/p/ffa473f6e524


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
全栈工程师
手记
粉丝
228
获赞与收藏
996

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消