vivo官網(wǎng)App模塊化開發(fā)方案-ModularDevTool
說明:本工具基于vivo互聯(lián)網(wǎng)客戶端團隊內(nèi)部開源的編譯管理工具開發(fā)。
一、背景
現(xiàn)在客戶端的業(yè)務(wù)越來越多,大部分客戶端工程都采用模塊化的開發(fā)模式,也就是根據(jù)業(yè)務(wù)分成多個模塊進行開發(fā),提高團隊效率。例如我們vivo官網(wǎng)現(xiàn)在的整體架構(gòu)如下圖,分為13個模塊,每個模塊是一個獨立代碼倉。
(注:為什么這么分,可以參考之前的一篇文章《??Android模塊化開發(fā)實踐???》)
二、痛點
完全隔離的代碼倉,使每個模塊更獨立,更易于代碼管理,但也帶來了一些問題。
1、開發(fā)階段,子倉開發(fā)以及集成開發(fā)調(diào)試,操作麻煩、易出錯、難跟蹤回溯
1.1、當(dāng)開發(fā)時涉及的模塊較多時,需要手動一個一個拉代碼,多個子倉的代碼操作非常麻煩,并且需要打開多個AndroidStudio進行開發(fā);
1.2、子倉集成到主倉開發(fā)調(diào)試,有兩種方式,但是都有比較大的缺點:
(1)方式1,子倉通過maven依賴,這種方式需要不斷的發(fā)布子倉的snapshot,主倉再更新snapshot,效率較低;
(2)方式2,子倉通過代碼依賴,也就是需要在主倉的settings.gradle中,手動include拉到本地的子倉代碼,然后在build.gradle中配置dependencies,配置繁瑣,容易出錯;
1.3、主倉對子倉的依賴,如果是部分maven依賴、部分代碼依賴,容易出現(xiàn)代碼沖突;
1.4、apk集成的子模塊aar和代碼,沒有對應(yīng)關(guān)系,排查問題時很難回溯。
2、版本發(fā)布階段,流程繁瑣,過多重復(fù)勞動,流程如下:
2.1、逐個修改子倉的版本,指定snapshot或release;
2.2、每個子倉需要提交修改版本號的代碼到git;
2.3、每個子倉都要手動觸發(fā)發(fā)布maven倉;
2.4、更新主倉對子倉依賴的版本;
2.5、構(gòu)建Apk;
2.6、如果用持續(xù)集成系統(tǒng)CI,則每個子倉都需要配置一個項目,再逐個啟動子倉的編譯,等子倉全部編譯完再啟動主倉編譯。
三、方案
針對上述問題,我們優(yōu)化的思路也很明確了,就是以自動化的方式解決繁瑣和重復(fù)的操作。最終開發(fā)了ModularDevTool,實現(xiàn)以下功能:
1、開發(fā)階段
1.1、在主倉中,管理所有子倉代碼(拉代碼、切分支及其他git操作),管理子倉相關(guān)信息(代碼倉路徑、分支、版本等);
1.2、只需要打開一個AS工程,即可進行所有倉的代碼開發(fā);
1.3、對子倉的兩種依賴方式(代碼依賴和maven依賴)一鍵切換,支持混合依賴(即部分倉代碼依賴,部分倉maven依賴);
1.4、編譯時輸出子模塊的版本及對應(yīng)commitid,便于回溯跟蹤代碼。
2、版本發(fā)布階段
2.1、只需要在主倉修改子倉版本號,子倉無需修改,省去子倉代碼修改和提交代碼過程;
2.2、CI上只要配一個主倉項目,實現(xiàn)一鍵編譯,包括子倉編譯aar(按依賴關(guān)系順序編譯)、上傳maven、編apk;
2.3、CI上支持3種編譯模式:
- OnlyApp:即只編譯主倉代碼生成apk(前提是子模塊已發(fā)布maven);
- publishSnapshot:即子倉編譯上傳snapshot版本,然后編譯主倉生成apk;
- publishRelease:即子倉編譯上傳release版本,然后編譯主倉生成apk。
四、ModularDevTool概覽
工具采用了shell腳本+gradle插件的方式實現(xiàn)的。
首先看下工程目錄概覽
1、submodules目錄是用來存放子倉代碼的,子倉代碼就是正常的工程結(jié)構(gòu),submodules目錄如下圖:
2、repositories.xml文件是用來配置子倉信息的,包括模塊名、代碼倉、分支、版本等,具體內(nèi)容如下:
3、vsub.sh腳本是工具各種功能的入口,比如:
- ./vsub.sh sync:拉取所有子模塊代碼,代碼存放在主工程下的submodules目錄中
- ./vsub.sh publish:一鍵編譯所有子倉,并發(fā)布aar到maven
4、subbuild目錄用來輸出子倉的git提交記錄,subError目錄用來輸出子倉編譯異常時的log。
五、關(guān)鍵功能實現(xiàn)
ModularDevTool主要功能分為兩類,一類是代碼管理,用于批量處理git操作;第二類是項目構(gòu)建,實現(xiàn)了動態(tài)配置子模塊依賴、子模塊發(fā)布等功能。
5.1 代碼管理
vsub.sh腳本中封裝了常用的git命令,用于批量處理子倉的git操作,實現(xiàn)邏輯相對簡單,利用shell腳本將git命令封裝起來。
比如 ./vsub.sh -pull的實現(xiàn)邏輯,首先是cd進入submodules目錄(submodules目錄存放了所有子倉代碼),然后遍歷進入子倉目錄執(zhí)行g(shù)it pull --rebase命令,從而實現(xiàn)一個命令完成對所有子倉的相同git操作,實現(xiàn)邏輯如下:
5.2 項目構(gòu)建
(1)Sync 功能
通過執(zhí)行./vsub.sh sync命令將所有子模塊的代碼拉取到主工程的submodules目錄中。
Sync命令有3個功能:
1)如果子倉代碼未拉取,則拉取代碼,并切換到repositories.xml中配置的devbranch;
2)如果子倉代碼已拉取,則切換到repositories.xml中配置的devbranch;
3)考慮到在一些場景(比如jenkins構(gòu)建),使用分支檢出代碼可能會存在異常,在sync命令后面加 -c 參數(shù),則會使用repositories.xml中配置的commitid檢出指定分支代碼。
Sync流程如下:
(2)子模塊依賴處理
在之前我們依賴不同子倉的代碼時,需要手動修改settings.gradle導(dǎo)入子模塊,然后修改build.gradle中的dependencies,如下圖。
團隊中每個人代碼的存放位置不同,在新版本拉完代碼后都需要手動配置一番,比較繁瑣。
基于sync功能已經(jīng)把所有的子倉代碼都拉到了submodules目錄中,現(xiàn)在我們項目在構(gòu)建時只需簡單配置local.properties即可(local.properties配置如下圖),確定哪些子模塊是代碼依賴,哪些子模塊是maven依賴。
子模塊依賴處理的流程如下:
(3)publish功能
通過執(zhí)行./vsub.sh publish命令實現(xiàn)一鍵編譯所有子模塊aar并上傳maven。
publish命令主要有4個功能:
1)如果子倉代碼未拉取,則自動拉取子倉代碼;
2)如果是發(fā)布snapshot版本,則切換到devbranch分支最新代碼,version中包含snapshot字符串的子模塊,編譯生成aar并上傳maven;否則,則直接跳過,不會編譯;
3)如果是發(fā)布release版本(即指定-a參數(shù)),則切換到commitid對應(yīng)的代碼,編譯生成release版本的aar,并上傳maven;
4)子倉的編譯上傳順序根據(jù)配置的priority優(yōu)先級來執(zhí)行。
注:上述的devbranch、version、commitid、priority等都是repositories.xml中的配置項。
publish發(fā)布子模塊的流程如下:
六、ModularDevTool接入
接入本方案的前提是項目采用多代碼倉的方式進行模塊化開發(fā)。具體接入步驟也比較簡單。
第一步,主倉依賴gradle插件modular_dev_plugin;
(該插件包含settings、tools、base、publish四個子插件,其中settings、tools和base插件配合實現(xiàn)子倉代碼管理、動態(tài)依賴處理,publish插件實現(xiàn)子倉的aar發(fā)布)
第二步,主倉的settings.gradle應(yīng)用settings插件,主倉的app build.gradle中應(yīng)用tools和base插件;
第三步,主倉根目錄添加repositories.xml配置文件和vsub腳本;
第四步,子倉依賴modular_dev_plugin,并應(yīng)用publish插件;
第五步,中間層的子倉(比如App→Shop→Lib,那Shop就是中間層子倉)對下一層子倉的依賴版本號改成占位符,項目構(gòu)建時會自動替換成repositories.xml中的版本號。如下圖:
至此,ModularDevTool就接入完成了。
七、現(xiàn)在的開發(fā)流程
基于這個工具,現(xiàn)在我們官網(wǎng)的開發(fā)流程如下:
第一步是clone主App倉代碼,checkout對應(yīng)開發(fā)分支,并在AndroidStudio打開工程;
第二步是修改repositories.xml配置,需要進行開發(fā)的子倉,修改devbranch為對應(yīng)開發(fā)分支,修改version為對應(yīng)版本號;
第三步,通過./vsub.sh sync命令,檢出所有子模塊代碼;
第四步,修改local.properties中子倉依賴的模式(maven依賴or代碼依賴),修改完成后點擊Sync一下,然后就可以正常進行代碼開發(fā)了,開發(fā)體驗與單工程多module模式完全一樣。
八、總結(jié)
這個工具已經(jīng)很成熟,在vivo錢包、vivo官網(wǎng)等項目已經(jīng)使用多年,通過該工具,開發(fā)階段,實現(xiàn)多業(yè)務(wù)模塊集成式開發(fā),解決代碼倉分散管理和手動配置依賴等繁瑣操作,發(fā)布階段,實現(xiàn)多種編譯模式以及一鍵編包能力,對于團隊的開發(fā)效率有很大提升,支撐官網(wǎng)app項目3+業(yè)務(wù)線并行迭代,并且代碼沖突降低50%以上。