android自己写组件化,得到App Android组件化方案解析

为什么要写这篇文章

组件化已经深得客户端开发大神们的认可,组件化确实进一步优化了客户端团队的开发效率,更适合大团队分组推进,理解组件化的思想,深入研究组件化的实现方案是很必要的。

在接触众多组件化的方案后,自己也萌生了想搭建一套集众家之所长的组件化方案。

而从【得到】组件化方案入手,主要是【得到】组件化开源的demo比较完整,日期也比较新。

这篇文章的主要目的是想研究一下【得到】组件化比其他组件化方案更优的点,就像得到官方文章中说的一样:

在设计之初参考了目前已有的组件化和插件化方案,站在巨人的肩膀上又加了一点自己的想法

综合各家之所长,再加上自己的一点想法,整理出自己习惯的一套组件化方案

得到App组件化的大概介绍

开源的组件化方案并不少,放出来的组件化文章就更多了,但是像【得到】技术团队这样连同方案和解析文章全部一起打包,毫无保留的开源给开发者的确实是少数。

只是官方文章难免站在了主人的角度来诠释框架的整体,对于一个刚刚接触这套框架的学习者来说还是有点难懂,所以我这里再次对这个方案的实现从一个学习者的角度梳理一下,对其他学习者应该也是有意义的。

【得到】组件化优缺点都比较明显

优点:代码隔离方案很实用,并且逻辑简单清晰好理解

缺点:暂时还没有加入 Activity注解-apt自动生成-ui路由 ,发布aar仍需改动isRunAlone的值。

【得到】组件化官方的解析文章中已经有放出项目的架构图,因为省略了一些模块,所以对于初学者来说看得不算是非常清晰,我这里有做了一版比较全的。

dd7d1a4b38338a4477b94afe8b47f17a.png

从图中我们可以看得出来

componentservice基本就是base moudle

业务组件与主host之间靠gradle.properties确定依赖关系,但这里只是依赖关系的标记而已,并没有直接依赖上,也就是开发期组件之间是不能直接调用的,否则编译会报错,从根本上杜绝了直接调用的问题。

所有业务组件统一进入build-gradle处理,在编译期自动添加依赖关系,也就是完成了【代码隔离】

【得到】组件化的代码隔离,主要靠两个步骤

UI路由方案的解读其实已经非常多,github上的明星项目就好几个呢,所以我就不过多解读了。

这里我们着重了解一下【得到】组件化有关于代码隔离的实现方案。

本文很少贴大段的源码,主要是想用尽可能简明的语音和清晰的图来说明实现方法。所以最好是熟读官网文章记录下自己的问题之后,一边对照我这篇解析文章,一边对照着demo源码来理解才是最佳途径。

主要靠两个步骤

build-gradle插件

componentservice服务接口

build-gradle的作用

b5ac9c583c62758194c69ebca69a997d.png

从图中可以看出包括主项目App在内的每一个moudle都通过在build.gradle文件中

apply plugin: 'com.dd.comgradle'

引入自定义插件build-gradle

而apply plugin 实际上是调用的gradle的project中的方法

void apply(Mapoptions)

d58c25a4eedc5f8c71c399766d5e0e1f.png

如果你疑问为什么调用方法没有括号,没有参数,请先了解一下Gradle DSl的基础知识和语法特性。深入理解Android之Gradle

每个moudle都调用了apply方法后,实际上都执行到了ComBuild.groovy中的

void apply(Project project) {}

至此就算明白了 每个moudle在编译期都会执行到ComBuild.groovy的apply方法中。

apply方法中做了这些事请:

调用getTaskInfo()方法,读取当前Task信息,标记是否是组装(assemble)Task,是否是调试(DEBUG)模式

如果是Assemble(组装类)的Task,调用fetchMainmodulename()方法,确定当前编译的moudle,从rootProject中读取mainmodulename的初始值

从gradle.properties中取出isRunAlone的值,根据isRunAlone执行不同的操作

如isRunAlone=true,则代表当前的moudle就是主项目,引入plugin: ‘com.android.application’插件

如果当前moudle是否是主moudle,且当前task是否为Assemble(组装类)Task,则根据gradle.properties中的debugComponent和compileComponent分情况自动添加依赖文件,组件发布的aar就是这里使用的。

根据每个moudle的build.gradle文件中isRegisterCompoAuto字段判断是否自动注册moudle所提供的服务,这里涉及到何时调用每个moudle中的IApplicationLike,什么方式调用?

0f21a376ceda9ed8178b65e6ed85d840.png

调用的方式有两种:

A. 编译期字节码插入的方式,就是扫描所有的ApplicationLike类后,自动写入调用代码,具体查看ComCodeTransform.groovy中的代码逻辑

B. 反射调用,类似下面的代码

Router.registerComponent("com.mrzhang.reader.applike.ReaderAppLike")

如isRunAlone=false,则代表当前的moudle是library,引入plugin: ‘com.android.library’插件,然后看是否是assembleRelease Task:

如果是assembleRelease,则发布组件aar

如果不是assembleRelease Task,则把当前moudle作为library随同主项目一起编译而已

componentservice服务接口的实现

相比build-gradle插件,componentservice服务接口的实现就非常简单了,官网博客中说是面向接口编程还是非常恰当的,如下图所示:

31fda86a94be163805dc1a61539732da.png

从图中可以看出,componentservice中的Router存放的所有组件所提供的服务,而Router本身只是一个map而已,原理非常简单

组件B的开发人员再编写好组件B之后,需要提供接口文档

组件A的开发人员想用组件B的服务时,就需要根据接口文档有关于组件B的服务描述中,找到组件B所提供的服务的名字,然后调用router.getService(服务全路径名);即可获取响应的服务

而面向接口编程其实说的是每个应用到服务的地方都是针对父类编程,以达到接口和实现的分离目的

由于在开发期是面对存放在componentservice目录下的服务父类编程,而在提供服务的组件中的IApplicationLike中注册了组件中关于服务的具体实现。

43ad569da07740fa42dac5b4916bbb5e.png

上面的文字描述可能还是不太明白,所以还是用图表示好了

e37f837a1031880769e0e6d02a799b14.png

总结

这是我对于【得到】组件化方案中的代码隔离部分的一个梳理,可能有些地方描述不清楚或者有理解错误,欢迎大家指正。

如有问题可以一起讨论,个人qq 278960878.

希望对大家有帮助!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值