美文网首页程序人生组件化模块化相关Android插件化
Android彻底组件化—代码和资源隔离

Android彻底组件化—代码和资源隔离

作者: 格竹子 | 来源:发表于2017-11-06 09:51 被阅读5557次

得到Android组件化方案已经开源,参见Android组件化方案开源。方案的解读文章是一个小的系列,这是系列的第三篇文章:
1、Android彻底组件化方案实践
2、Android彻底组件化demo发布
3、Android彻底组件化-代码和资源隔离
4、Android彻底组件化—UI跳转升级改造
5、Android彻底组件化—如何使用Arouter

最近Google正式推出AS3.0版本,同时gradle插件也升级为3.0.0,目前各大开源库都在做gradle3.0.0的兼容,我也把得到开源的组件化方案JIMU进行了升级,结论是:JIMU在gradle3.0上是没有兼容问题的,可以直接使用。关于如何迁移到gradle3.0.0,请参见官方迁移指南

虽然没有兼容问题,但在升级的过程中也收获了意外之喜,那就是发现gradle3.0.0对代码隔离的支持越来越好。为什么对“代码隔离”这么关注呢?大家可以回顾前两篇文章Android彻底组件化方案实践Android彻底组件化demo发布,在这两篇文章中提到的JIMU组件化方案,被我冠以“彻底”二字,虽然有些说大话,但主要是为了强调JIMU与之前其他组件化方案的不同之处就在于,JIMU实现了组件之间的绝对隔离,不同组件之间在代码开发阶段是完全不可见的,是一种彻底解耦的思想。为了实现这种隔离,我人为在编译和运行期做了一次判断和区分,既在编译期间(开发期间)组件之间没有任何依赖关系,但在打包和运行时,再偷偷添加依赖。具体可以参见前两篇文章和github源码

不得不说,当时这种实现是迫不得已,我本来想直接使用gradle提供的功能来做这种隔离,其实gradle也的确提供一个类似的功能,那就是apk依赖语法,其作用就是保证依赖库只在运行期间对外可见,但在编译期间是不可见的。按说这已经满足我的要求了,但是遇到了一个坑:在gradle2.+版本,apk依赖只能是jar,不能是aar,但是我们的组件因为含有各种资源,输出产物就是aar!所以最终选择了放弃apk这种语法。

而在最新的gradle3.0.0上,apk被替换为runtimeOnly语法,其作用还是一样的,但是我发现runtimeOnly可以添加aar依赖!这的确让我很兴奋,这不就是我梦寐以求的功能吗?有了这个尚方宝剑,组件化的方案就可以做的更薄了啊。于是我对在得到app上进行了实验,结论是:runtimeOnly的确可以解决一些问题,但是还不够。下面我从代码隔离、资源隔离和调试切换(单独和集成)三个方便仔细阐述,也顺便再讲一下JIMU所能实现的功能。

一、代码隔离

在讲代码隔离之前,先大致看一下gradle3.0.0对添加依赖的语法变化。

首先compile被废弃了,而是分成了两个:implementation和api,其中api与之前的compile功能基本一致,不再赘述;implementation就比较高级了,其作用就是,使用implementation添加的依赖不会再编译期间被其他组件引用到,但在运行期间是完全可见的。这也是一种代码隔离。举个例子,

组件A依赖lib1,既A implementation lib1
组件B依赖组件A,既B api A

在gradle3.0.0之前,B是完全可以引用到lib1里面的类的,但是现在B在编译期间就做不到了,只能在运行期可以。这种思想有点类似于“下属的下属不是你的下属”的思想。但是这种隔离在组件之间是不起作用的,在上面的例子中A的所有类对B还是完全可见的,也就是没有做任何隔离的。不过implementation的确是一种有效减少编译时间的方式,还是上面的例子,lib1发生了变化,现在只需要编译A就可以了,而在之前B有可能也使用到了lib1,所以需要同时编译B和A。按照官方建议,大部分情况下都应该使用implementation来进行添加依赖。

此外还有两种变化,原来的apk语法被runtimeOnly取代,provided被compileOnly取代,其作用还是没变。上文也讲了,runtimeOnly有个极大的改动就是可以支持aar了,但是compileOnly还是只能支持jar!

先做一个小结,目前gradle3.0.0的四种语法的功能和代码隔离效果见下图:

四种语法的功能和代码隔离效果

从上图可以看出,在代码隔离效果上,runtimeOnly的效果是最好的!但是就可以直接使用了吗,答案是否定的

二、资源隔离

在前面的文章中,一直在强调代码隔离,其实组件之间的完全隔离还有一层就是资源隔离,否则还是容易造成组件之间的耦合。这个在文章的“单独调试”章节中提到了一句,就是每个组件都需要指定一个资源前缀resourcePrefix,以避免集成后资源名冲突的问题。也就是说,一个彻底的组件化不仅要做到代码不能直接引用,资源也是不能引用的!

但是runtimeOnly目前还做到资源隔离,我在JIMU的开源库上做了试验,app通过runtimeOnly引用sharecomponent组件,虽然sharecomponent的代码是不可见了,但是资源还是可以被app直接使用的并能成功运行。

从这一点上看,直接替换成runtimeOnly是不行的,为了达到这种效果,目前还是需要像JIMU一样,人为的加一层控制,所以从组件化方案的角度上看并没有变的更薄,不过幸好JIMU已经很简单了,有一定的gradle基础的人可以比较容易的理解。

三、调试切换

除了上面说的资源隔离导致不能直接用runtimeOnly之外,还有一个使用上的问题需要解决,这也是JIMU中compbuild插件提供的一个功能:自动切换单独调试和集成调试。在单独调试时,组件是一个application工程,其输出产物是apk文件,而在集成调试时,被依赖的组件是一个library工程,其输出产物是aar文件。对于runtimeOnly来说,对aar和jar是支持的,但是不能支持apk,所以如果想在单独调试和集成调试之间切换的话,需要人工修改runalone配置并修改build.gradle配置文件,然后还需要sync之后才能生效,这种修改是相当繁琐的。

在JIMU中,这个问题的解决是通过“智能”识别当前要调试的组件来解决的,对于要调试的组件将其设置为application工程,而将其依赖的其他组件默默修改为library工程,这种修改是即时生效的,对开发者是完全透明的。开发者直接点击AS的run功能区就可以随意的调试任意组件。AS的run功能区的图如下:


随意的调试切换

四、总结

综上所述,我们对JIMU和gradle3.0.0做几点总结:
(1)升级到gradle3.0.0之后,可以继续使用JIMU,不需要专门做兼容
(2)gradle3.0.0提供了implementation和runtimeOnly两种语法,它们都能实现一定程度的代码隔离效果,建议大家在今后优先使用
(3)implementation和runtimeOnly目前在资源隔离和调试切换上还不能满足组件化的要求,所以还是需要使用JIMU提供的完全隔离和随意切换功能。

在JIMU的源码中我增加了gradle3.0.0分支,依赖语法做了相应的替换源码地址:DDComponent

JIMU的讨论群,群号693097923,欢迎大家加入:


进群请扫码

相关文章

网友评论

  • 买榴莲的欧巴:build-gradle作为主要核心,但是相关的讲解,和代码中的备注很少。希望大神针对核心的build-gradle写一篇文章
  • brock:格竹子一词来源王阳明吗:smile:
    brock:@格竹子 大神在哪个城市工作啊😄
    格竹子:@brock 对的
  • _孑孓_:大佬要去头条的消息已经传播到整个圈子了:smiley:
  • initialjie:请问可以单独对build-gradle这个模块作详细讲解吗?谢谢
    initialjie:@格竹子 谢谢大佬的回复,源码这部分注释不是很多,看起来还是有点废劲:joy:
    格竹子:@initialjie 文中已经有说明了吧,源码上也有一些注释,你可以看一下
  • 55b080e73fc7:文档写的很好,赞一个,请问你应该看过微信架构升级的文档吧 https://www.qcloud.com/community/article/441423,你对里面pins粒度的代码隔离有研究吗?我这边通过SourceSet把原来多个module放到了一个module下面也能编译通过,但是原来module间代码隔离没有了,这个问题有什么好的解决办法吗?
    格竹子:@Kobewylb 1,你看看底层的库都是全部组件用到的吗,如果只有一个组件用到的库,就应该放到组件中引入,这样可以减少底层库的个数。2,如果底层库需要频道变动,是不是不应该放到maven上?先以module的方式运行一段时间,稳定之后在发布到maven。3,如果都解决不了,建议三层依赖库的源码放在一个工程里,设置一些全局参数,改动版本后统一执行make,一次就可以搞定,不需要三次执行
    55b080e73fc7:那我再问一个问题,比如目前已经组件化的工程A包含(app)+(module1)+(module2)+(底层组件maven远程依赖),但是底层组件存在三层以上的层级依赖 公司通用业务层->非公司UI层+通用业务层+net+common,每次修改相对底层的库需要一层层make&uplaod maven,请问有什么好的方案来快速make和uplaod吗
    格竹子:@Kobewylb 我也是昨晚这套组件化之后才看到微信的文章,对于pins的实现不是很明白,文章讲的比较简略。代码隔离我目前的解决方式就是开源的DDComponent里面的编译期隔离的方法,目前看这种方式还是很有效的。
  • shunxir:能不能写一些关于gradle使用方面的文章谢谢
    格竹子:@shunxir 暂时没时间写这块的文章,现在正在对开源项目进行一次大的调整,忙完这块再看吧
  • actinbar:学习中,打call:+1::+1::+1:
  • fa47c82221a6:棒棒棒
  • d47bd9ba6e68:楼主你们组件化方案用的路由方案是哪一家的?
    格竹子:@ZircoN 请看github上的源码和前两篇文章,是完全自己写的方案
  • leobert:过来打call啦😀,写的真棒👍
    格竹子:@leobert 😀😀
  • woitaylor:看你的插件是不是要学会gradle?有没有什么好的资源
    格竹子:@woitaylor 我也没有系统学习过,都是现学现用。最好的资料就是官方文档和源码了,可能看起来太费劲,建议多google几篇讲解文章就可以了
  • shijunxing:很好
    格竹子:@shijunxing 是的
    shijunxing:@格竹子 听说阁下要去头条了?
    格竹子:谢谢:smile:

本文标题:Android彻底组件化—代码和资源隔离

本文链接:https://www.haomeiwen.com/subject/tcwopxtx.html