模組化的優勢有很多,一程式碼分離,結構清晰;二多工協同開發,而且自己模組單獨執行也更輕量。等等。最近在調研各種實現方案,這是我的自己想出來的一種。
話不多說,直接分享我的操作步驟,然後我可能會與其他實現方式做個對比。
原有專案結構
為了實現模組化,前期我們已經根據應用功能場景,進行了module拆分,為實現模組化靠攏。專案簡化結構如下圖
APP
是應用的入口module,我把他做得很簡單,裡邊可以說就一個歡迎頁Activity。BaseModule
是一些跟基本封裝。ModuleA、B、C
是期望單獨執行的Module。模組間的跳轉我用的是ARouter
,這塊暫不多介紹。
我們知道,每一個Project都是由多個module組成,而settings.gradle中通過include方式引入這些module,所以一開始就在想如果能在編譯時動態的引入module那不就是很簡單了嗎。
操作步驟
一 gradle.properties配置
在專案根目錄的gradle.properties中定義一個變數,為了做到變數值的見名知意,我用的String型別的
# ↓全量編譯模式
#DEVELOP_MODE="all"
#
# ↓單ModuleA模組編譯模式
DEVELOP_MODE="module-a"
#
# ↓單ModuleB模組編譯模式
#DEVELOP_MODE="module-b"
#
# ↓單ModuleC模組編譯模式
#DEVELOP_MODE="module-c"
#
...
複製程式碼
二 settings.gradle區分
根據gradle.properties中配置的不同執行模式,在settings中做簡單的if else 判斷,include不同的module
include ':APP', 'BaseModule'
if (DEVELOP_MODE == "\"module-a\"") {
include ':ModuleA'
} else if (DEVELOP_MODE == "\"module-b\"") {
include ': ModuleB'
} else if (DEVELOP_MODE == "\"module-c\"") {
include ': ModuleC'
} else {
include ': ModuleA', ': ModuleB', ': ModuleC'
}
複製程式碼
在這裡有個寫法上需要注意的是String型別的module-a
需要加\
轉義,甚至呼叫startsWith
這樣的API都要這樣寫DEVELOP_MODE.startsWith("\"module")
有人說這裡不需要區分,直接include所有module即可。我嘗試後發現確實可以,但仍會執行多餘module的gradle編譯,徒增編譯時間,所以最好區分。
三 APP的gradle配置
上面的module關係依賴圖中我們看到,APP依賴了A、B、C這三個module。在這裡,我們也是需要根據gradle.properties中配置的不同執行模式,動態引入依賴
if (DEVELOP_MODE == "\"module-a\"") {
implementation project(':ModuleA')
} else if (DEVELOP_MODE == "\"module-b\"") {
implementation project(':ModuleB')
} else if (DEVELOP_MODE == "\"module-c\"") {
implementation project(':ModuleC')
} else {
implementation project(':ModuleA')
implementation project(':ModuleB')
implementation project(':ModuleC')
}
複製程式碼
好了,一個簡單的模組化就實現了,如果想單獨執行ModuleA,就將gradle.properties
中的DEVELOP_MODE="module-a"
這一行解開,其他註釋掉,sync Now完後直接執行就OK了
擴充
一個正常的商業專案,肯定不像我前面的專案圖一樣簡單,只有1個APP、1個Base、2個Module。我專案真實情況是類似中間的模組ABC這層就有20多個,而且不止一層;Base這層module也有五六個。不使用JIMU(積木)那種Android元件化框架的原因之一就是專案不是簡簡單單,關係整齊的這種依賴關係。
而且,在我們應用裡,要想使用ModuleB,必須帶著ModuleA的結果資料。要想B模組化後能使用,這該怎麼做?需要的資料可能有:資料庫、SharedPreferences、File檔案,網路請求及合理的引數。
我們的做法是,為這種非正式的模組化執行新增一個,專門初始化假資料的module。在APP的歡迎頁中跳轉時判斷,如果是模組化執行,直接往這個假資料Module跳,通過這個Module初始化好所有的資料後,再往真正的目標Module跳。
而需要準備的資料中,網路請求及合理的引數的準備,也有很多實現方案。比如就用真實的請求,比如本機執行服務。對於我做這個調研,沒有找後端支援,也想過自己搭後臺伺服器,但是一想,搭好了伺服器,也是簡單的返回造好的假json串資料。所以乾脆,本地處理算了,這時候okhttp的攔截器就是一個很好的應用了。我直接在攔截器中,判斷請求的path,返回假的json串不就行了。
當然,還有很多模組化需要用到的小技術點,那就需要見招拆招了。
與其他模組化方式對比
(1)有一種模組化是這樣寫的,在ModuleA的gradle檔案中
if(isBuildModule.toBoolean()){
apply plugin: 'com.android.application'
}else{
apply plugin: 'com.android.library'
}
...
sourceSets {
main {
if (isBuildModule.toBoolean()) {
manifest.srcFile 'src/main/debug/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/release/AndroidManifest.xml'
}
}
}
//isBuildModule是在gradle.properties中宣告
isBuildModule=false
複製程式碼
這樣寫的繁瑣之處是
- 需要在每個Module的gradle.properties中宣告這樣一個區分application還是library。
- 準備兩套Manifest。
- 要想單獨執行某個模組還得每次去改動settings的include,和APP的gradle中的依賴。
(2)使用JIMU(積木)這種Android元件化框架
它整合好之後的使用,雖然也很簡單。但是框架的接入也是需要新增很多東西,比如每個module的properties中都需要進行配置。而且框架的一個缺點就是我們開發人員不知道它怎麼實現的,遇到的編譯問題也更不好查。
(3)我這樣寫的優缺點
優點
- 條理清晰,定義的每個地方是什麼作用都很清楚
- 不修改原有module內的業務邏輯,在外邊準備好所需資料有點沙盒似的設計。
- 不只能單模組執行。也可能,多個模組組成一個業務線,整體執行這個業務線也很好實現。
- 切換執行模組時,只開關gradle.properties裡的配置就行。
缺點
- 新配置一個模組化需要在gradle.properties、settings.gradle、APP的gradle,這3個地方都做響應的配置。需要配的模組化執行多了,if else 類的判斷也會增多,程式碼行數也會增加,略顯繁瑣。但相對於切換模組的簡便,這些是值得的。
最後求助各位道友,如果,您們有其他什麼好的思路,歡迎你們和我一起交流