作者:vivo 互联网客户端团队- Wang Zhenyu

本文首要讲述了Android客户端模块化开发的痛点及处理方案,详细讲解了方案的完成思路和详细完成方法。

阐明:本东西依据vivo互联网客户端团队内部开源的编译办理东西开发。

一、背景

现在客户端的事务越来越多,大部分客户端工程都选用模块化的开发形式,也便是依据事务分成多个模块进行开发,提高团队功率。例如咱们vivo官网现在的全体架构如下图,分为13个模块,每个模块是一个独立代码仓。

(注:为什么这么分,可以参考之前的一篇文章《Android模块化开发实践》)

vivo官网App模块化开发方案-ModularDevTool

二、痛点

彻底隔离的代码仓,使每个模块更独立,更易于代码办理,但也带来了一些问题

vivo官网App模块化开发方案-ModularDevTool

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,完成以下功用:

vivo官网App模块化开发方案-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插件的方法完成的。

首先看下工程目录概览

vivo官网App模块化开发方案-ModularDevTool

1、submodules目录是用来寄存子仓代码的,子仓代码便是正常的工程结构,submodules目录如下图:

vivo官网App模块化开发方案-ModularDevTool

2、repositories.xml文件是用来装备子仓信息的,包含模块名、代码仓、分支、版别等,详细内容如下:

<?xml version="1.0" encoding="utf-8" ?>
<repositories>
        <!-- 一个repository表明一个库房,一个库房下或许会有多个module -->
    <repository>
        <!-- 库房称号,可以随意界说,首要用于本地快速辨认 -->
        <name>lib模块</name>
        <!-- 上传至maven时的groupid -->
        <group>com.vivo.space.lib</group>
        <!-- 装备库房中的一切子模块,假如多个module就添加多个module标签 -->
        <modules>
            <module>
                <!-- 上传至maven时的artifactid -->
                <artifactid>vivospace_lib</artifactid>
                <!-- 上传至maven时的版别号 -->
                <version>5.9.8.0-SNAPSHOT</version>
                <!-- 编译次序优先级,越小优先级越高 -->
                <priority>0</priority>
            </module>
        </modules>
        <!-- 留意库房地址中的个人ssh称号要运用$user占位符替代 -->
        <repo>ssh://$user@smartgit:xxxx/VivoCode/xxxx_lib</repo>
        <!-- 开发分支,脚本用来主动切换到该分支 -->
        <devbranch>feature_5.9.0.0_xxx_dev</devbranch>
        <!-- 打release包时必须强制指定commitId,保证取到指定代码  -->
        <commitid>cbd4xxxxxx69d1</commitid>
    </repository>
    <!-- 多个库房就添加多个repository -->
    ...
</repositories>

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指令封装起来。

vivo官网App模块化开发方案-ModularDevTool

比方 ./vsub.sh -pull的完成逻辑,首先是cd进入submodules目录(submodules目录寄存了一切子仓代码),然后遍历进入子仓目录履行git pull –rebase指令,从而完成一个指令完成对一切子仓的相同git操作,完成逻辑如下:

<!-- ./vsub.sh -pull代码逻辑 -->
 cd submodules
 path=$currPath
 files=$(ls $path)
 for fileName in $files
 do
     if [ ! -d $fileName ]
     then
         continue
     fi
     cd $fileName
     echo -e "\033[33mEntering $fileName\033[0m"
     git pull --rebase
     cd ..
 done

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流程如下:

vivo官网App模块化开发方案-ModularDevTool

(2)子模块依靠处理

在之前咱们依靠不同子仓的代码时,需求手动修正settings.gradle导入子模块,然后修正build.gradle中的dependencies,如下图。

<!-- settings.gradle -->
include ':app',':module_name_1',':module_name_2',':module_name_3'...
project(':module_name_1').projectDir = new File('E:/AndroidCode/module_name_1/code/')
project(':module_name_2').projectDir = new File('E:/AndroidCode/module_name_2/code/')
project(':module_name_3').projectDir = new File('E:/AndroidCode/module_name_3/code/')
...
<!-- build.gradle -->
dependencies {
    api fileTree(dir: 'libs', include: ['*.jar'])
    // 事务子模块 begin
    api project (':module_name_1')
    api project (':module_name_2')
    api project (':module_name_3')
    // 事务子模块 end
}
...

团队中每个人代码的寄存位置不同,在新版别拉完代码后都需求手动装备一番,比较繁琐。

依据sync功用现已把一切的子仓代码都拉到了submodules目录中,现在咱们项目在构建时只需简略装备local.properties即可(local.properties装备如下图),确认哪些子模块是代码依靠,哪些子模块是maven依靠。

<!-- 其间key module_name_x表明子模块名,value 0表明maven依靠,1表明代码依靠,默认是maven依靠,也便是,假如不装备某些子模块则默认maven依靠 -->
module_name_1=0
module_name_2=0
module_name_3=1
module_name_4=1
module_name_5=1
module_name_6=1

子模块依靠处理的流程如下:

vivo官网App模块化开发方案-ModularDevTool

(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发布子模块的流程如下:

vivo官网App模块化开发方案-ModularDevTool

六、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中的版别号。如下图:

dependencies {
    // 对lib仓的依靠,原来是依靠详细的版别号,现在改成“unified”占位符,项目构建时会主动替换成repositories.xml中的版别号
    api "com.vivo.space.lib:vivospace_lib:unified"
}

至此,ModularDevTool就接入完成了。

七、现在的开发流程

依据这个东西,现在咱们官网的开发流程如下:

第一步是clone主App仓代码,checkout对应开发分支,并在AndroidStudio翻开工程;

第二步是修正repositories.xml装备,需求进行开发的子仓,修正devbranch为对应开发分支,修正version为对应版别号;

vivo官网App模块化开发方案-ModularDevTool

**第三步,**经过./vsub.sh sync指令,检出一切子模块代码;

第四步,修正local.properties中子仓依靠的形式(maven依靠or代码依靠),修正完成后点击Sync一下,然后就可以正常进行代码开发了,开发体验与单工程多module形式彻底相同。

八、总结

这个东西现已很老练,在vivo钱包、vivo官网等项目现已运用多年,经过该东西,开发阶段,完成多事务模块集成式开发,处理代码仓涣散办理和手动装备依靠等繁琐操作,发布阶段,完成多种编译形式以及一键编包才能,关于团队的开发功率有很大提升,支撑官网app项目3+事务线并行迭代,而且代码抵触降低50%以上。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。