前言
随着APP需求的不断迭代和团队人员规模的增加,代码的坏味道越来越多,编译时长变长、代码冲突增加、新需求的工期变长。面对这些问题模块化拆分是一个好的解决思路。合理的模块化拆分可以降低代码的耦合度,方便单个模块的调试、升级、测试等。本文将对Android模块化拆分做一个探索。
目标

宿主:不做具体的功能实现,只负责组合业务模块,组装成一个完成的APP,即可以实现一套代码生成多APP
业务模块:将项目拆分成一个一个独立的module,可独立运行
基础组件层:与业务无关、与项目无关,所有项目都可以复用,包含各种开源库以及与业务无关的自研库
优点
架构灵活,焦点分离
耦合低,模块间可自由组合、分解
方便单个模块功能调试、升级、测试,提高开发效率
多人协作只负责单独模块,互不干扰
模块化实战-广告模块化拆分
现状
三个联运包:oppo、huawei、xiaomi
七家广告sdk:广点通、头条、快手、百度、oppo、小米、华为
16个广告位
联运包通过分支开发方式,每次发版前需要合并代码
目标
一份代码生成三个联运包和普通包
广告位广告提供者全支持,例如目前书架只支持广点通原生广告,改造后后台可随意配置广告提供商,客户端皆可支持
新广告sdk的极速接入
实现方案
广告流程接口化
ARouter动态发现广告实现
广告流程

广告流程接口化
所有广告的加载流程都一致,将流程抽象到抽象类AdBaseImpl中,具体的广告sdk实现AdBaseImpl
ARouter动态发现广告实现
拆分各个广告的module,module中包括广告的aar、不同广告类型的实现类(继承AdBaseImpl),module只对外提供一个ARouter的IAdInitProvider,在IAdInitProvider中初始化相应的广告sdk,并将实现类注册到AdFactory

普通包不依赖oppo、华为、小米的module,所以普通包apk ARouter init时是不能发现oppo、华为、小米的广告实现。

oppo联运包不依赖华为、小米的module,所以普通包apk ARouter init时是能发现oppo的广告实现,但是不能发现华为、小米的广告实现。

所有广告位可以根据providerId获取到具体的广告实现类,根据AdBaseImpl的流程填充广告
接入文档
新建module,添加广告的aar等;
module的build.gradle中,使用implementation方式依赖aar,保证app中不会引用到aar中的代码;ARouter相关配置;依赖 base module
module中build.gradle


实现AdBaseImpl

实现IAdInitProvider接口,在ARouterConstant中定义ARouter的path,path的规范是/moduleName/(provider/activity/service)/业务/功能,例如/baiduAd/provider/ad/init
IAdInitProvider#initAdSAdk()中初始化sdk,也可以在使用的时候再延迟初始化;调用AdFactory.registerAdInterface注册广告的实现类

AdFactory的sInitPaths增加这个path
只有IAdInitProvider的实现类是public的,其他类都设置为包内可见,防止app中误用
踩坑之旅
ARouter初始化路由映射表的流程,如下图,
如果是debug或版本更新时重新扫描dex文件获取对应的路由文件,否则会从SharedPreferences缓存中获取路由路由文件 
代码本身没有问题,这样做可以加快初始化速度。
但对于版本号相同的不同的联运包之间相互覆盖却会出现ClassNotFound问题,不同联运包的代码是不相同的。
问题解决方案:
通过arouter-register实现。Arouter自动加载路由表的插件是使用的通过gradle插桩技术在编译期插入代码来达到自动加载路由表信息,保证了路由表和代码的一致性。接入步骤

app的build.gradle中增加 apply plugin: 'com.alibaba.arouter'
根目录的build.gradle dependencies 中增加classpath "com.alibaba:arouter-register:$arouter_register_version"。arouter_register_version表示最新的arouter-register版本
编译后LogisticsCenter#loadRouterMap会注册所有的路由信息




