转载:https://www.jianshu.com/p/81d2e0132a10
首先说明,以上不是标题党,而是最近的一些感想,或许我觉得看完这篇文章,只要肯花时间,去进一步消化,组件化方案不难,难的就是拆分的过程,容我一一道来!!
继上家公司把组件化做完之后,经历了线上考验,依然坚挺着。由于个人原因(发展+穷......),四月份辞职了,前往现在的新公司,最近被安排的任务,依然是组件化搭建设计,顺便也做了一次OJT的内部分享,把上家公司组件化的一些感想经验做下分享,以下纯属个人观点,如果有些不对,望各位大佬指出。另外也是对之前写的一篇文章的完善和修改。
首先先把效果图呈上。
一、概念
谈起组件化,会不由的联想到模块化,插件化的概念,他们三者究竟区别在哪?模块化其实是一个很通用的,对于与整个技术领域,当代码冗余到一定程度,将其进行分层解耦,当某个功能,某个控件很多地方会使用,我们把它抽出来,其实都叫模块化。对应于Android领域,就是组件化和插件化。组件化最终打包生产的Apk只有一个,你可以在编译期间把单个组件编译成apk来调试运行。而插件化可以最终打包成多个apk,每个插件可以在apk运行时进行加载。
二、实战
为什么进行组件化,我就简单的说下。因为网上最近关于组件化的文章也很多。自己总结了四个。如上图。图里很详细,其实主要就是把项目解耦,提高构建,开发的效率,另外为之后进行插件化铺路,不过目前如果做插件化对其兼容性考验很大,但是组件化没有这个问题。
做组件化之前首先就是设计方案,因为公司和项目不是你一个人的,你需要设计可行性的方案,让团队信服。因为之前阿里Andfix刚出来的时候,就做过源码分享,到后面的开源的插件化框架Small。本来计划用第三方的,省时省力,但是不省心,因为强扭的瓜不甜,不能硬上,要温柔....万一出问题了不好改,而且不适合现在的项目。那么只能硬着头皮,埋头干!
先给大家看看效果图,后面再慢慢解释。
如果不进行组件化,相信基本每个公司每个项目发展到一定程度都会变成上图的情况,改进之后如下图。为什么两种最后的结构图不同呢?因为他们应用的组件跳转和通信不同,前者是最开始使用的,后者是改进之后的,后面详细说。
这里必须提一下,做组件化,必须对gradle有一定了解和熟悉,不了解的可以把这个视频学完,《新一代构建工具gradle》受益颇多。这个也是做组件化的前提!!
在方案和设计图画好后,进行组件化的第一步就是打造底层Common库。
Common库,一般包含一些基础的公共模块,公共类库,通用控件,基础的BaseActivity,BaseApplication等。再进行拆分时,可以先新建一个module,然后把这些文件通过移动的形式放过去,不要复制,因为这样上层的引用也会自动的改变,不然你得手动一个个去更改。在组件化拆分过程中,不要太心急,可以先把之前的项目作为一个main_module,然后从里面把一个拆的差不多了,再拆另外一个,个人不建议前期并行。并行会导致混乱。
三、方法
总结了一下,组件化方案,基本都必须解决如下几个问题。
1.所谓组件化,就是要做到,打包发布是一个apk,开发阶段,每个组件可以单独调试运行。那么如何自由的在module和library间切换。如何处理好AndroidManifest,gradle.build究竟是application还是library?
2.如果我们在library时添加application,那么整体打包就会报错,但是library切换到module必须要application,怎么解决呢?
3.很多真实业务场景,我们需要A组件跳转到B组件的某个界面,或者给它传递参数。另外,如果A组件化执行完某个任务,需要通知B组件更新,怎么处理?
4.A组件依赖你引入的一个库B,库B里面又依赖库C,但是D组件直接依赖库C,这个时候编译就会报错。
5.真正组件化开发的时候,基本每个组件完全隔离,A组件开发人员对组件A的资源的命名可能会和其他组件冲突。
好了,来一一说明怎么解决,但是解决的前提,还是特别推荐,没有gradle基础的,可以把上面关于gradle的视频看完。
第一个问题:
在项目的gradle.properties里面配置一个全局的常量isModule,通过更改它的值来控制module和library的切换。
在组件各自的buid.gradle里面配置如下,
大概的意思就是,根据isModule的值来判断是用什么地方的文件,还有plugin用什么。这里不做过多解释,demo很详细。
第二个问题:
从前面的配置可以看出,exclude,"debug/**如果是library状态,就不使用debug下面的文件。
可以在debug里面定义所需的moduleApplication,继承放到底层common库的BaseApplication。组件里面的application只需要实现简单的逻辑就行。
第三个问题:
上面最终的架构效果图不一样,主要是引用的第三方库不同,多进程通信方案,学习成本有点高,配置有点麻烦(不是说该方案不好,只是不太适用当前项目),后面改成阿里开源的ARouter。
感兴趣的可以详细的看下,这里不做扩展。简单的介绍一下ARouter和EventBus.
如上图,在B组件某个界面添加@Route注解,然后A组件如果想跳转到B的某个界面,就可以如上代码设置。
EventBus是用来解决,A组件执行完某个任务,需要B组件刷新,本来也可以用广播解决,但是广播不方便管理。但是EventBus使用和广播差不多,都需要注册,发送,处理事件。
第四个问题:
可以使用gradle脚本,exclude 把重复依赖的包去掉,还有种做法,是把依赖文件统一放在一起,gradle会自动使用最新版本替换老版本。我是使用后者。
第五个问题:
可以在组件buid.gradle,添加 resourcePrefix project.name + '_'的配置。不过该配置只针对xml文件,图片资源需要在团队统一命令规范,一般推荐使用组件名加图片名。
四、风险与反思
我一直坚信凡事都会有好坏,就看自己如何抉择。组件化是一项大工程,对项目整个架构更改,基本需要测试把大部分功能都测一遍。(保险起见),其次就是编译时间加长,为什么会这么说?网上很多资料明明说了会加快编译时间。编译时间变长,是真心体会。因为组件化你前期没有办法一步到位,大神除外。前期组件会以library形式存在,而不是aar,就会导致编译时间加长。但是后期稳定成熟,打包成aar了,就会快很多。其次组员需要一定学习成本,这个就是为什么把多进程换成ARouter,ARouter学习成本会小很多。
另外就是对产品的要求,产品在设计的时候也需要遵循组件化。在前期时,我们的底层Common会拆分很多公共模块,这些模块能不动尽量不动,因为你的改动,可能导致其他的依赖有问题。最后就是发版的检查,发版前,需要确保混淆,组件版本是最新版本。
五、Tips
1.因为很多组件都需要buid.gradle,里面基本很多东西都是一样的,可以在主工程新建一个文件夹,然后统一用一个配置,这样方便管理,如图。
2.单独组件开发时,如何知道怎么调用别的组件的情况,可以在每个组件定义一个arouter.json文件,统一管理。不过这个也有点麻烦,每次定义的时候,需要手动在项目的arouter.json文件里添加,如果大家有更好的方案麻烦和我说下。
3.A组件想调用B组件的某个方法,注意,不是跳转界面。其实最开始的demo演示也有。本质是使用ARouter。首先在底层的Common库定义一个接口集成IProvider,然后在B组件实现该方法,最后A组件里面,获取接口的实例,然后调用该方法。
4.GIT组件化部署
可以参考Git 工具 - 子模块
5.Demo地址
作者:为梦拼命的攻城狮
链接:https://www.jianshu.com/p/81d2e0132a10
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。