109

android彻底组件化番外篇-gradle3.0.0

 6 years ago
source link: https://juejin.im/post/59ffc0c651882512a860b1b4
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

android彻底组件化番外篇-gradle3.0.0

2017年11月06日 01:55 ·  阅读 3320

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

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

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

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

一、代码隔离

在讲代码隔离之前,先大致看一下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目前还做到资源隔离,我在DDComponent的开源库上做了试验,app通过runtimeOnly引用sharecomponent组件,虽然sharecomponent的代码是不可见了,但是资源还是可以被app直接使用的并能成功运行。

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

三、调试切换

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

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

随意的调试切换

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

在DDComponent的源码中我增加了gradle3.0.0分支,依赖语法做了相应的替换,欢迎大家继续支持“得到”app出品的组件化方案,源码地址:https://github.com/mqzhangw/AndroidComponent


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK