vivo 官网 App 模块化开发方案 -ModularDevTool
作者:vivo 互联网客户端团队- Wang Zhenyu
本文主要讲述了 Android 客户端模块化开发的痛点及解决方案,详细讲解了方案的实现思路和具体实现方法。
说明:本工具基于 vivo 互联网客户端团队内部开源的编译管理工具开发。
一、背景
现在客户端的业务越来越多,大部分客户端工程都采用模块化的开发模式,也就是根据业务分成多个模块进行开发,提高团队效率。例如我们 vivo 官网现在的整体架构如下图,分为 13 个模块,每个模块是一个独立代码仓。
(注:为什么这么分,可以参考之前的一篇文章《Android模块化开发实践》)
二、痛点
完全隔离的代码仓,使每个模块更独立,更易于代码管理,但也带来了一些问题。
1、开发阶段,子仓开发以及集成开发调试,操作麻烦、易出错、难跟踪回溯
1.1、当开发时涉及的模块较多时,需要手动一个一个拉代码,多个子仓的代码操作非常麻烦,并且需要打开多个 AndroidStudio 进行开发;
1.2、子仓集成到主仓开发调试,有两种方式,但是都有比较大的缺点:
(1)方式 1,子仓通过 maven 依赖,这种方式需要不断的发布子仓的 snapshot,主仓再更新 snapshot,效率较低;
(2)方式 2,子仓通过代码依赖,也就是需要在主仓的 settings.gradle 中,手动 include 拉到本地的子仓代码,然后在 build.gradle 中配置 dependencies,配置繁琐,容易出错;
1.3、主仓对子仓的依赖,如果是部分 maven 依赖、部分代码依赖,容易出现代码冲突;
1.4、apk 集成的子模块 aar 和代码,没有对应关系,排查问题时很难回溯。
2、版本发布阶段,流程繁琐,过多重复劳动,流程如下:
2.1、逐个修改子仓的版本,指定 snapshot 或 release;
2.2、每个子仓需要提交修改版本号的代码到 git;
2.3、每个子仓都要手动触发发布 maven 仓;
2.4、更新主仓对子仓依赖的版本;
2.5、构建 Apk;
2.6、如果用持续集成系统 CI,则每个子仓都需要配置一个项目,再逐个启动子仓的编译,等子仓全部编译完再启动主仓编译。
三、方案
针对上述问题,我们优化的思路也很明确了,就是以自动化的方式解决繁琐和重复的操作。最终开发了 ModularDevTool,实现以下功能:
1、开发阶段
1.1、在主仓中,管理所有子仓代码(拉代码、切分支及其他 git 操作),管理子仓相关信息(代码仓路径、分支、版本等);
1.2、只需要打开一个 AS 工程,即可进行所有仓的代码开发;
1.3、对子仓的两种依赖方式(代码依赖和 maven 依赖)一键切换,支持混合依赖(即部分仓代码依赖,部分仓 maven 依赖);
1.4、编译时输出子模块的版本及对应 commitid,便于回溯跟踪代码。
2、版本发布阶段
2.1、只需要在主仓修改子仓版本号,子仓无需修改,省去子仓代码修改和提交代码过程;
2.2、CI 上只要配一个主仓项目,实现一键编译,包括子仓编译 aar(按依赖关系顺序编译)、上传 maven、编 apk;
2.3、CI 上支持 3 种编译模式:
OnlyApp:即只编译主仓代码生成 apk(前提是子模块已发布 maven);
publishSnapshot:即子仓编译上传 snapshot 版本,然后编译主仓生成 apk;
publishRelease:即子仓编译上传 release 版本,然后编译主仓生成 apk。
四、ModularDevTool 概览
工具采用了 shell 脚本+gradle 插件的方式实现的。
首先看下工程目录概览
1、submodules 目录是用来存放子仓代码的,子仓代码就是正常的工程结构,submodules 目录如下图:
2、repositories.xml 文件是用来配置子仓信息的,包括模块名、代码仓、分支、版本等,具体内容如下:
3、vsub.sh 脚本是工具各种功能的入口,比如:
./vsub.sh sync:拉取所有子模块代码,代码存放在主工程下的 submodules 目录中
./vsub.sh publish:一键编译所有子仓,并发布 aar 到 maven
4、subbuild 目录用来输出子仓的 git 提交记录,subError 目录用来输出子仓编译异常时的 log。
五、关键功能实现
ModularDevTool 主要功能分为两类,一类是代码管理,用于批量处理 git 操作;第二类是项目构建,实现了动态配置子模块依赖、子模块发布等功能。
5.1 代码管理
vsub.sh 脚本中封装了常用的 git 命令,用于批量处理子仓的 git 操作,实现逻辑相对简单,利用 shell 脚本将 git 命令封装起来。
比如 ./vsub.sh -pull 的实现逻辑,首先是 cd 进入 submodules 目录(submodules 目录存放了所有子仓代码),然后遍历进入子仓目录执行 git pull --rebase 命令,从而实现一个命令完成对所有子仓的相同 git 操作,实现逻辑如下:
5.2 项目构建
(1)Sync 功能
通过执行./vsub.sh sync 命令将所有子模块的代码拉取到主工程的 submodules 目录中。
Sync 命令有 3 个功能:
1)如果子仓代码未拉取,则拉取代码,并切换到 repositories.xml 中配置的 devbranch;
2)如果子仓代码已拉取,则切换到 repositories.xml 中配置的 devbranch;
3)考虑到在一些场景(比如 jenkins 构建),使用分支检出代码可能会存在异常,在 sync 命令后面加 -c 参数,则会使用 repositories.xml 中配置的 commitid 检出指定分支代码。
Sync 流程如下:
(2)子模块依赖处理
在之前我们依赖不同子仓的代码时,需要手动修改 settings.gradle 导入子模块,然后修改 build.gradle 中的 dependencies,如下图。
团队中每个人代码的存放位置不同,在新版本拉完代码后都需要手动配置一番,比较繁琐。
基于 sync 功能已经把所有的子仓代码都拉到了 submodules 目录中,现在我们项目在构建时只需简单配置 local.properties 即可(local.properties 配置如下图),确定哪些子模块是代码依赖,哪些子模块是 maven 依赖。
子模块依赖处理的流程如下:
(3)publish 功能
通过执行./vsub.sh publish 命令实现一键编译所有子模块 aar 并上传 maven。
publish 命令主要有 4 个功能:
1)如果子仓代码未拉取,则自动拉取子仓代码;
2)如果是发布 snapshot 版本,则切换到 devbranch 分支最新代码,version 中包含 snapshot 字符串的子模块,编译生成 aar 并上传 maven;否则,则直接跳过,不会编译;
3)如果是发布 release 版本(即指定-a 参数),则切换到 commitid 对应的代码,编译生成 release 版本的 aar,并上传 maven;
4)子仓的编译上传顺序根据配置的 priority 优先级来执行。
注:上述的 devbranch、version、commitid、priority 等都是 repositories.xml 中的配置项。
publish 发布子模块的流程如下:
六、ModularDevTool 接入
接入本方案的前提是项目采用多代码仓的方式进行模块化开发。具体接入步骤也比较简单。
第一步,主仓依赖 gradle 插件 modular_dev_plugin;
(该插件包含 settings、tools、base、publish 四个子插件,其中 settings、tools 和 base 插件配合实现子仓代码管理、动态依赖处理,publish 插件实现子仓的 aar 发布)
第二步,主仓的 settings.gradle 应用 settings 插件,主仓的 app build.gradle 中应用 tools 和 base 插件;
第三步,主仓根目录添加 repositories.xml 配置文件和 vsub 脚本;
第四步,子仓依赖 modular_dev_plugin,并应用 publish 插件;
第五步,中间层的子仓(比如 App→Shop→Lib,那 Shop 就是中间层子仓)对下一层子仓的依赖版本号改成占位符,项目构建时会自动替换成 repositories.xml 中的版本号。如下图:
至此,ModularDevTool 就接入完成了。
七、现在的开发流程
基于这个工具,现在我们官网的开发流程如下:
第一步是 clone 主 App 仓代码,checkout 对应开发分支,并在 AndroidStudio 打开工程;
第二步是修改 repositories.xml 配置,需要进行开发的子仓,修改 devbranch 为对应开发分支,修改 version 为对应版本号;
第三步,通过./vsub.sh sync 命令,检出所有子模块代码;
第四步,修改 local.properties 中子仓依赖的模式(maven 依赖 or 代码依赖),修改完成后点击 Sync 一下,然后就可以正常进行代码开发了,开发体验与单工程多 module 模式完全一样。
八、总结
这个工具已经很成熟,在 vivo 钱包、vivo 官网等项目已经使用多年,通过该工具,开发阶段,实现多业务模块集成式开发,解决代码仓分散管理和手动配置依赖等繁琐操作,发布阶段,实现多种编译模式以及一键编包能力,对于团队的开发效率有很大提升,支撑官网 app 项目 3+业务线并行迭代,并且代码冲突降低 50%以上。
版权声明: 本文为 InfoQ 作者【vivo互联网技术】的原创文章。
原文链接:【http://xie.infoq.cn/article/f99ca1ccf03227c9842260c10】。文章转载请联系作者。
评论