1犀呼、為什么要項目組件化
隨著 APP 版本不斷的迭代贮尖,新功能的不斷增加,業(yè)務(wù)也會變的越來越復雜煮盼,APP 業(yè)務(wù)模塊 的數(shù)量有可能還會繼續(xù)增加短纵,而且每個模塊的代碼也變的越來越多,這樣發(fā)展下去單一工程 下的 APP 架構(gòu)勢必會影響開發(fā)效率僵控,增加項目的維護成本香到,每個工程師都要熟悉如此之多 的代碼,將很難進行多人協(xié)作開發(fā)报破,而且 Android 項目在編譯代碼的時候電腦會非秤凭停卡,又 因為單一工程下代碼耦合嚴重充易,每修改一處代碼后都要重新編譯打包測試梗脾,導致非常耗時, 最重要的是這樣的代碼想要做單元測試根本無從下手盹靴,所以必須要有更靈活的架構(gòu)代替過去 單一的工程架構(gòu)炸茧。
- 目前比較普遍使用的 Android APP 技術(shù)架構(gòu),往往是在一個界面中存在大量的業(yè)務(wù) 邏輯稿静,而業(yè)務(wù)邏輯中充斥著各種網(wǎng)絡(luò)請求梭冠、數(shù)據(jù)操作等行為,整個項目中也沒有模塊的概念改备, 只有簡單的以業(yè)務(wù)邏輯劃分的文件夾控漠,并且業(yè)務(wù)之間也是直接相互調(diào)用、高度耦合在一起的;
-
業(yè)務(wù)包之間的依賴過于復雜
image.png
上圖單一工程模型下的業(yè)務(wù)關(guān)系盐捷,總的來說就是:你中有我偶翅,我中有你,相互依賴碉渡,無法分 離聚谁。然而隨著產(chǎn)品的迭代,業(yè)務(wù)越來越復雜爆价,隨之帶來的是項目結(jié)構(gòu)復雜度的極度增加垦巴,此時我 們會面臨如下幾個問題:
1.實際業(yè)務(wù)變化非常快铭段,但是單一工程的業(yè)務(wù)模塊耦合度太高骤宣,牽一發(fā)而動全身;
2.對工程所做的任何修改都必須要編譯整個工程序愚;
3.功能測試和系統(tǒng)測試每次都要進行憔披;
4.團隊協(xié)同開發(fā)存在較多的沖突.不得不花費更多的時間去溝通和協(xié)調(diào),并且在開發(fā)過程中爸吮, 任何一位成員沒辦法專注于自己的功能點芬膝,影響開發(fā)效率;
5.不能靈活的對業(yè)務(wù)模塊進行配置和組裝形娇; 為了滿足各個業(yè)務(wù)模塊的迭代而彼此不受影響锰霜,更好的解決上面這種讓人頭疼的依賴關(guān)系, 就需要整改 App 的架構(gòu)桐早。
2癣缅、如何組件化
-
組件化工程模型
image.png
上圖是組件化工程模型,為了方便理解這張架構(gòu)圖哄酝,下面會列舉一些組件化工程中用到的名 詞的含義:
名詞 | 含義 |
---|---|
集成模式 | 所有的業(yè)務(wù)組件被“app 殼工程”依賴友存,組成一個完整的 APP |
組件模式 | 可以獨立開發(fā)業(yè)務(wù)組件,每一個業(yè)務(wù)組件就是一個 APP |
app 殼工程 | 負責管理各個業(yè)務(wù)組件陶衅,和打包 apk屡立,沒有具體的業(yè)務(wù)功能 |
業(yè)務(wù)組件 | 根據(jù)公司具體業(yè)務(wù)而獨立形成一個的工程 |
功能組件 | 提供開發(fā) APP 的某些基礎(chǔ)功能,例如多媒體文件播放等 |
Main 組件 | 屬于業(yè)務(wù)組件搀军,指定 APP 啟動頁面膨俐、主界面 |
Common組件 | 屬于功能組件,支撐業(yè)務(wù)組件的基礎(chǔ)罩句,提供多數(shù)業(yè)務(wù)組件需要的功能吟策,例 如提供網(wǎng)絡(luò)請求功能,打印日志,統(tǒng)一管理第三方依賴庫 |
- 組件化工程依賴關(guān)系
Android APP 組件化架構(gòu)的目標是告別結(jié)構(gòu)臃腫的止,讓各個業(yè)務(wù)變得相對獨立,業(yè)務(wù)組件在組件模式下可以獨立開發(fā)着撩,而在集成模式下又可以變?yōu)?arr 包集成到“app 殼工程”中诅福,組成一 個完整功能的 APP匾委; 從組件化工程模型中可以看到,業(yè)務(wù)組件之間是獨立的氓润,沒有關(guān)聯(lián)的赂乐,這些業(yè)務(wù)組件在集 成模式下是一個個 library,被 app 殼工程所依賴咖气,組成一個具有完整業(yè)務(wù)功能的 APP 應(yīng)用挨措, 但是在組件開發(fā)模式下,業(yè)務(wù)組件又變成了一個個 application崩溪,它們可以獨立開發(fā)和調(diào)試浅役, 由于在組件開發(fā)模式下,業(yè)務(wù)組件們的代碼量相比于完整的項目差了很遠伶唯,因此在運行時可 以顯著減少編譯時間觉既。
- 組件化帶來的好處
這是組件化工程模型下的業(yè)務(wù)關(guān)系,業(yè)務(wù)之間將不再直接引用和依賴乳幸,而是通過“路由”這樣 一個中轉(zhuǎn)站間接產(chǎn)生聯(lián)系瞪讼,而 Android 中的路由實際就是對 URL Scheme 的封裝; 如此規(guī)模大的架構(gòu)整改需要付出更高的成本粹断,還會涉及一些潛在的風險符欠,但是整改后的架構(gòu) 能夠帶來很多好處:
1、加快業(yè)務(wù)迭代速度瓶埋,各個業(yè)務(wù)模塊組件更加獨立希柿,不再出現(xiàn)業(yè)務(wù)耦合情況;
2悬赏、穩(wěn)定的公共模塊采用依賴庫方式狡汉,提供給各個業(yè)務(wù)線使用,減少重復開發(fā)和維護工作量闽颇;
3盾戴、迭代頻繁的業(yè)務(wù)模塊采用組件方式,各業(yè)務(wù)研發(fā)可以互不干擾兵多、提升協(xié)作效率尖啡,并控制 產(chǎn)品質(zhì)量;
4剩膘、為新業(yè)務(wù)隨時集成提供了基礎(chǔ)衅斩,所有業(yè)務(wù)可上可下,靈活多變怠褐;
5畏梆、降低團隊成員熟悉項目的成本,降低項目的維護難度;
6奠涌、加快編譯速度宪巨,提高開發(fā)效率;
7溜畅、控制代碼權(quán)限捏卓,將代碼的權(quán)限細分到更小的粒度;
3慈格、組件化實施流程
1)組件模式和集成模式的轉(zhuǎn)換
Android Studio 中的 Module 主要有兩種屬性怠晴,分別為:
1、application 屬性浴捆,可以獨立運行的 Android 程序蒜田,也就是我們的 APP; apply plugin: ‘com.android.application’
2汤功、library 屬性物邑,不可以獨立運行,一般是 Android 程序依賴的庫文件滔金; apply plugin: ‘com.android.library’
Module 的屬性是在每個組件的 build.gradle 文件中配置的色解,當我們在組件模式開發(fā)時,業(yè) 務(wù)組件應(yīng)處于 application 屬性餐茵,這時的業(yè)務(wù)組件就是一個 Android App科阎,可以獨立開發(fā)和 調(diào)試;而當我們轉(zhuǎn)換到集成模式開發(fā)時忿族,業(yè)務(wù)組件應(yīng)該處于 library 屬性锣笨,這樣才能被我們 的“app 殼工程”所依賴,組成一個具有完整功能的 APP道批; 但是我們?nèi)绾巫尳M件在這兩種模式之間自動轉(zhuǎn)換呢错英?總不能每次需要轉(zhuǎn)換模式的時候去每 個業(yè)務(wù)組件的 Gralde 文件中去手動把 Application 改成 library 吧?如果我們的項目只 有兩三個組件那么這個辦法肯定是可行的隆豹,手動去改一遍也用不了多久椭岩,但是在大型項目中 我們可能會有十幾個業(yè)務(wù)組件,再去手動改一遍必定費時費力璃赡,這時候就需要程序員發(fā)揮下 懶的本質(zhì)了判哥。 試想,我們經(jīng)常在寫代碼的時候定義靜態(tài)常量碉考,那么定義靜態(tài)常量的目的什么呢塌计?當一個常 量需要被好幾處代碼引用的時候,把這個常量定義為靜態(tài)常量的好處是當這個常量的值需要 改變時我們只需要改變靜態(tài)常量的值侯谁,其他引用了這個靜態(tài)常量的地方都會被改變锌仅,做到了 一次改變章钾,到處生效;根據(jù)這個思想热芹,那么我們就可以在我們的代碼中的某處定義一個決定 業(yè)務(wù)組件屬性的常量伍玖,然后讓所有業(yè)務(wù)組件的 build.gradle 都引用這個常量,這樣當我們改 變了常量值的時候剿吻,所有引用了這個常量值的業(yè)務(wù)組件就會根據(jù)值的變化改變自己的屬性; 可是問題來了串纺?靜態(tài)常量是用 Java 代碼定義的丽旅,而改變組件屬性是需要在 Gradle 中定義 的,Gradle 能做到嗎纺棺? Gradle 自動構(gòu)建工具有一個重要屬性榄笙,可以幫助我們完成這個事情。每當我們用 AndroidStudio 創(chuàng)建一個 Android 項目后祷蝌,就會在項目的根目錄中生成一個文 件 gradle.properties茅撞,我們將使用這個文件的一個重要屬性:在 Android 項目中的任何一 個 build.gradle 文件中都可以把 gradle.properties 中的常量讀取出來;那么我們在上面提 到解決辦法就有了實際行動的方法巨朦,首先我們在 gradle.properties 中定義一個常量 值 isModule(是否是組件開發(fā)模式米丘,true 為是,false 為否): # 每次更改“isModule”的值后糊啡,需要點擊 "Sync Project" 按鈕 isModule=false 然后我們在業(yè)務(wù)組件的 build.gradle 中讀取 isModule拄查,但是 gradle.properties 還有一個重 要屬性: gradle.properties 中的數(shù)據(jù)類型都是 String 類型,使用其他數(shù)據(jù)類型需要自行 轉(zhuǎn)換棚蓄;也就是說我們讀到 isModule 是個 String 類型的值堕扶,而我們需要的是 Boolean 值, 代碼如下:
if (isModule.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
這樣我們第一個問題就解決了梭依,當然了 每次改變 isModule 的值后稍算,都要同步項目才能生 效;
2)組件之間 AndroidManifest 合并問題
在 AndroidStudio 中每一個組件都會有對應(yīng)的 AndroidManifest.xml役拴,用于聲明需要的權(quán) 限糊探、Application、Activity扎狱、Service侧到、Broadcast 等,當項目處于組件模式時淤击,業(yè)務(wù)組件的 AndroidManifest.xml 應(yīng)該具有一個 Android APP 所具有的的所有屬性匠抗,尤其是聲明 Application 和要 launch 的 Activity,但是當項目處于集成模式的時候污抬,每一個業(yè)務(wù)組件的 AndroidManifest.xml 都要合并到“app 殼工程”中汞贸,要是每一個業(yè)務(wù)組件都有自己的 Application 和 launch 的 Activity绳军,那么合并的時候肯定會沖突,試想一個 APP 怎么可能會 有多個 Application 和 launch 的 Activity 呢矢腻? 但是大家應(yīng)該注意到這個問題是在組件開發(fā)模式和集成開發(fā)模式之間轉(zhuǎn)換引起的問題门驾,而在 上一節(jié)中我們已經(jīng)解決了組件模式和集成模式轉(zhuǎn)換的問題,另外大家應(yīng)該都經(jīng)歷過將 Android 項目從 Eclipse 切換到 AndroidStudio 的過程多柑,由于 Android 項目在 Eclipse 和 AndroidStudio 開發(fā)時 AndroidManifest.xml 文件的位置是不一樣的奶是,我們需要在 build.gradle 中指定下 AndroidManifest.xml 的位置,AndroidStudio 才能讀取到 AndroidManifest.xml竣灌,這樣解決辦法也就有了聂沙,我們可以為組件開發(fā)模式下的業(yè)務(wù)組件再 創(chuàng)建一個 AndroidManifest.xml,然后根據(jù) isModule 指定 AndroidManifest.xml 的文件 路徑初嘹,讓業(yè)務(wù)組件在集成模式和組件模式下使用不同的 AndroidManifest.xml及汉,這樣表單 沖突的問題就可以規(guī)避了
上圖是組件化項目中一個標準的業(yè)務(wù)組件目錄結(jié)構(gòu),首先我們在 main 文件夾下創(chuàng)建一個 module 文件夾用于存放組件開發(fā)模式下業(yè)務(wù)組件的 AndroidManifest.xml屯烦,而AndroidStudio 生成的 AndroidManifest.xml 則依然保留坷随,并用于集成開發(fā)模式下業(yè)務(wù)組件 的表單;然后我們需要在業(yè)務(wù)組件的 build.gradle 中指定表單的路徑驻龟,代碼如下:
sourceSets {
main {
if (isDebugModel.toBoolean()) {
manifest.srcFile 'src/main/java/debug/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/AndroidManifest.xml'
}
}
}
這樣在不同的開發(fā)模式下就會讀取到不同的 AndroidManifest.xml 温眉,然后我們需要修改這 兩個表單的內(nèi)容以為我們不同的開發(fā)模式服務(wù)。
3)全局 Context 的獲取及組件數(shù)據(jù)初始化
在Common組件中創(chuàng)建BaseApplication 然后在業(yè)務(wù)組件中debug文件夾下集成BaseApplication 在debug模式下的AndroidManifest.xml中聲明DebugApplication. 這樣在開發(fā)者模式下就可以有自己的DebugApplication了,同時可以在里面初始化一些自己本模塊需要的原始數(shù)據(jù).而BaseApplication提供了getContext()方法且在Common模塊里面不會因為模式的切換導致代碼無法訪問.
sourceSets {
main {
if (isDebugModel.toBoolean()) {
manifest.srcFile 'src/main/java/debug/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/AndroidManifest.xml'
//集成開發(fā)模式下排除 debug 文件夾中的所有 Java 文件
java { exclude 'debug/**' }
}
}
}
4)library 依賴問題
- 第三方包和我們自己的包存在重復加載導致編譯不過
解決辦法:根據(jù)組件名排除或者根據(jù)包名排除
下面以排除 support-v4 庫為例:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation ("com.jude:easyrecyclerview:$rootProject.easyRecyclerVersion")
{
exclude module: 'support-v4'//根據(jù)組件名排除
exclude group: 'android.support.v4'//根據(jù)包名排除
}
}
- 第三方依賴庫統(tǒng)一管理
前面介紹的 Common 庫的作用之一就是統(tǒng)一依賴開源庫迅脐,因為其他業(yè)務(wù)組件都依賴 了 Common 庫芍殖,所以這些業(yè)務(wù)組件也就間接依賴了 Common 所依賴的開源庫。
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
testImplementation deps.junit
androidTestImplementation deps.runner
androidTestImplementation deps.espresso_core
implementation deps.appcompat
//網(wǎng)絡(luò)
api deps.lifecycle
api deps.okhttp
api deps.logging_interceptor
api deps.retrofit
api deps.adapter_rxjava2
api deps.converter_gson
api deps.rxandroid
api deps.rxjava
api deps.rxlifecycle
}
5)組件之間調(diào)用和通信
在組件化開發(fā)的時候谴蔑,組件之間是沒有依賴關(guān)系豌骏,我們不能在使用顯示調(diào)用來跳轉(zhuǎn)頁面了, 因為我們組件化的目的之一就是解決模塊間的強依賴問題隐锭,假如現(xiàn)在要從 A 業(yè)務(wù)組件跳轉(zhuǎn) 到業(yè)務(wù) B 組件窃躲,并且要攜帶參數(shù)跳轉(zhuǎn),這時候怎么辦呢钦睡?而且組件這么多怎么管理也是個 問題蒂窒,這時候就需要引入“路由”的概念了,由本文開始的組件化模型下的業(yè)務(wù)關(guān)系圖可知路 由就是起到一個轉(zhuǎn)發(fā)的作用荞怒。
這里我推薦使用ARouter詳細使用就不贅述了,參考如下兩個鏈接
https://mp.weixin.qq.com/s/ao__wU3tNS2y6dh-wULb-A
https://github.com/alibaba/ARouter/blob/master/README_CN.md
6)組件之間資源名沖突
建議模塊創(chuàng)建時里面的資源文件統(tǒng)一前綴命名規(guī)則.
4洒琢、組件化項目的工程類型
1)app 殼工程
app 殼工程是從名稱來解釋就是一個空殼工程,沒有任何的業(yè)務(wù)代碼褐桌,也不能有 Activity衰抑, 但它又必須被單獨劃分成一個組件,而不能融合到其他組件中荧嵌,是因為它有如下幾點重要功 能:
app 殼工程中聲明了我們 Android 應(yīng)用的 Application呛踊,這個 Application 必須繼承自 Common 組件中的 BaseApplication(如果你無需實現(xiàn)自己的 Application 可以直接在表單 聲明 BaseApplication)砾淌,因為只有這樣,在打包應(yīng)用后才能讓 BaseApplication 中的 Context 生效谭网,當然你還可以在這個 Application 中初始化我們工程中使用到的庫文件汪厨,還可以在這 里解決 Android 引用方法數(shù)不能超過 65535 的限制,對崩潰事件的捕獲和發(fā)送也可以在這 里聲明愉择。
app 殼工程的 AndroidManifest.xml 是我 Android 應(yīng)用的根表單劫乱,應(yīng)用的名稱、圖標 以及是否支持備份等等屬性都是在這份表單中配置的锥涕,其他組件中的表單最終在集成開發(fā)模 式下都被合并到這份 AndroidManifest.xml 中要拂。
app 殼工程的 build.gradle 是比較特殊的,app 殼不管是在集成開發(fā)模式還是組件開 發(fā)模式站楚,它的屬性始終都是:com.android.application,因為最終其他的組件都要被 app 殼 工程所依賴搏嗡,被打包進 app 殼工程中窿春,這一點從組件化工程模型圖中就能體現(xiàn)出來,所以 app 殼工程是不需要單獨調(diào)試單獨開發(fā)的采盒。另外 Android 應(yīng)用的打包簽名旧乞,以及 buildTypes 和 defaultConfig 都需要在這里配置,而它的 dependencies 則需要根據(jù) isModule 的值分別 依賴不同的組件磅氨,在組件開發(fā)模式下 app 殼工程只需要依賴 Common 組件尺栖,或者為了防止 報錯也可以根據(jù)實際情況依賴其他功能組件,而在集成模式下 app 殼工程必須依賴所有在 應(yīng)用 Application 中聲明的業(yè)務(wù)組件烦租,并且不需要再依賴任何功能組件延赌。
2)功能組件和 Common 組件
- 功能組件是為了支撐業(yè)務(wù)組件的某些功能而獨立劃分出來的組件,功能實質(zhì)上跟項目中引入 的第三方庫是一樣的叉橱,功能組件的特征如下:
- 功能組件的 AndroidManifest.xml 是一張空表挫以,這張表中只有功能組件的包名;
- 功能組件不管是在集成開發(fā)模式下還是組件開發(fā)模式下屬性始終是: com.android.library窃祝,所以功能組件是不需要讀取 gradle.properties 中的 isModule 值的掐松; 另外功能組件的 build.gradle 也無需設(shè)置 buildTypes ,只需要 dependencies 這個功能 組件需要的 jar 包和開源庫粪小。
- Common 組件除了有功能組件的普遍屬性外大磺,還具有其他功能:
- Common 組件的 AndroidManifest.xml 不是一張空表,這張表中聲明了我們 Android 應(yīng)用用到的所有使用權(quán)限 uses-permission 和 uses-feature探膊,放到這里是因為在組件開發(fā) 模式下杠愧,所有業(yè)務(wù)組件就無需在自己的 AndroidManifest.xm 聲明自己要用到的權(quán)限了。
- Common 組件的 build.gradle 需要統(tǒng)一依賴業(yè)務(wù)組件中用到的 第三方依賴庫和 jar 包突想, 例如我們用到的 ARouter殴蹄、Okhttp 等等究抓。
- Common 組件中封裝了 Android 應(yīng)用的 Base 類和網(wǎng)絡(luò)請求工具盔几、圖片加載工具等等啥刻, 公用的 widget 控件也應(yīng)該放在 Common 組件中;業(yè)務(wù)組件中都用到的數(shù)據(jù)也應(yīng)放于 Common 組件中郭脂,例如保存到 SharedPreferences 和 DataBase 中的登陸數(shù)據(jù)稽荧;
- Common 組件的資源文件中需要放置項目公用的 Drawable橘茉、layout、sting姨丈、dimen畅卓、 color 和 style 等等,另外項目中的 Activity 主題必須定義在 Common 中蟋恬,方便和 BaseActivity 配合保持整個 Android 應(yīng)用的界面風格統(tǒng)一翁潘。
3)業(yè)務(wù)組件和 Main 組件
- 業(yè)務(wù)組件就是根據(jù)業(yè)務(wù)邏輯的不同拆分出來的組件,業(yè)務(wù)組件的特征如下:
- 業(yè)務(wù)組件中要有兩張 AndroidManifest.xml歼争,分別對應(yīng)組件開發(fā)模式和集成開發(fā)模式.
- 業(yè)務(wù)組件在集成模式下是不能有自己的 Application 的拜马,但在組件開發(fā)模式下又必須實現(xiàn) 自己的 Application 并且要繼承自 Common 組件的 BaseApplication,并且這個 Application 不能被業(yè)務(wù)組件中的代碼引用沐绒,因為它的功能就是為了使業(yè)務(wù)組件從 BaseApplication 中獲 取的全局 Context 生效俩莽,還有初始化數(shù)據(jù)之用。
- 業(yè)務(wù)組件有 debug 文件夾乔遮,這個文件夾在集成模式下會從業(yè)務(wù)組件的代碼中排除掉扮超,所 以 debug 文件夾中的類不能被業(yè)務(wù)組件強引用,例如組件模式下的 Application 就是置于 這個文件夾中蹋肮,還有組件模式下開發(fā)給目標 Activity 傳遞參數(shù)的用的 launch Activity 也應(yīng) 該置于 debug 文件夾中出刷;
- 業(yè)務(wù)組件必須在自己的 build.gradle 中根據(jù) isModule 值的不同改變自己的屬性,在 組件模式下是:com.android.application坯辩,而在集成模式下 com.android.library巷蚪;同時還需 要在 build.gradle 配置資源文件,如 指定不同開發(fā)模式下的 AndroidManifest.xml 文件路徑濒翻, 排除 debug 文件夾等屁柏;業(yè)務(wù)組件還必須在 dependencies 中依賴 Common 組件,并且引入 ActivityRouter 的注解處理器 annotationProcessor有送,以及依賴其他用到的功能組件淌喻。
下面是一份普通業(yè)務(wù)組件的 build.gradle 文件:
if (isModule.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
...
sourceSets {
main {
if (isModule.toBoolean()) {
manifest.srcFile 'src/main/module/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/AndroidManifest.xml' //集成開發(fā)模式下排除 debug 文件夾中的所有 Java 文件 java
{
exclude 'debug/**'
}
}
}
}
...
- Main 組件除了有業(yè)務(wù)組件的普遍屬性外,還有一項重要功能:
1雀摘、Main 組件集成模式下的 AndroidManifest.xml 是跟其他業(yè)務(wù)組件不一樣的裸删,Main 組件的 表單中聲明了我們整個 Android 應(yīng)用的 launch Activity,這就是 Main 組件的獨特之處阵赠;所 以我建議 SplashActivity涯塔、登陸 Activity 以及主界面都應(yīng)屬于 Main 組件肌稻,也就是說 Android 應(yīng)用啟動后要調(diào)用的頁面應(yīng)置于 Main 組件。
5匕荸、組件化項目的混淆方案
組件化項目的 Java 代碼混淆方案采用在集成模式下集中在 app 殼工程中混淆爹谭,各個業(yè)務(wù) 組件不配置混淆文件。集成開發(fā)模式下在 app 殼工程中 build.gradle 文件的 release 構(gòu)建類 型中開啟混淆屬性榛搔,其他 buildTypes 配置方案跟普通項目保持一致诺凡,Java 混淆配置文件也 放置在 app 殼工程中,各個業(yè)務(wù)組件的混淆配置規(guī)則都應(yīng)該在 app 殼工程中的混淆配置文 件中添加和修改践惑。 之所以不采用在每個業(yè)務(wù)組件中開啟混淆的方案腹泌,是因為 組件在集成模式下都被 Gradle 構(gòu)建成了 release 類型的 arr 包,一旦業(yè)務(wù)組件的代碼被混淆尔觉,而這時候代碼中又出現(xiàn)了 bug凉袱,將很難根據(jù)日志找出導致 bug 的原因;另外每個業(yè)務(wù)組件中都保留一份混淆配置文件 非常不便于修改和管理侦铜,這也是不推薦在業(yè)務(wù)組件的 build.gradle 文件中配置 buildTypes (構(gòu)建類型)的原因绑蔫。
6、工程的 build.gradle 和 gradle.properties 文件
1)組件化工程的 build.gradle 文件
在組件化項目中因為每個組件的 build.gradle 都需要配置 compileSdkVersion泵额、 buildToolsVersion 和 defaultConfig 等的版本號,而且每個組件都需要用到 annotationProcessor携添,為了能夠使組件化項目中的所有組件的 build.gradle 中的這些配置 都能保持統(tǒng)一嫁盲,并且也是為了方便修改版本號,我們統(tǒng)一在 Android 工程根目錄下的 build.gradle 中定義這些版本號烈掠,當然為了方便管理 Common 組件中的第三方開源庫的版本 號羞秤,最好也在這里定義這些開源庫的版本號,然后在各個組件的 build.gradle 中引用 Android 工程根目錄下的 build.gradle 定義的版本號左敌,組件化工程的 build.gradle 文件代碼如下:
...
ext {
// Sdk and tools
//localBuildToolsVersion 是 gradle.properties 中的數(shù)據(jù) buildToolsVersion = localBuildToolsVersion compileSdkVersion = 25
minSdkVersion = 16
targetSdkVersion = 25
versionCode = 1
versionName = "1.0"
javaVersion = JavaVersion.VERSION_1_8 // App dependencies version
supportLibraryVersion = "25.3.1"
retrofitVersion = "2.1.0"
glideVersion = "3.7.0"
loggerVersion = "1.15"
eventbusVersion = "3.0.0"
gsonVersion = "2.8.0"
photoViewVersion = "2.0.0" //需檢查升級版本 annotationProcessor = "1.1.7"
routerVersion = "1.2.2"
easyRecyclerVersion = "4.4.0"
cookieVersion = "v1.0.1"
toastyVersion = "1.1.3"
...
2)組件化工程的 gradle.properties 文件
- 首先在Android工程的 gradle.properties 中分別定義兩個常量:localBuildToolsVersion 和 localGradlePluginVersion瘾蛋,分別表示 buildToolsVersion 和 Gradle Build Tools 的版本號:
# 為自動化出包配置(因為每個開發(fā)的電腦壞境不一致)
localBuildToolsVersion=25.0.3
# 這個值一般跟你的AndroidStudio版本號一致
localGradlePluginVersion=2.3.2
- 然后在Android工程的 build.gradle 中引用 localGradlePluginVersion:
dependencies {
//classpath "com.android.tools.build:gradle:$localGradlePluginVersion"
//$localGradlePluginVersion是gradle.properties中的數(shù)據(jù)
classpath "com.android.tools.build:gradle:$localGradlePluginVersion"
}
- 在組件的build.gradle中引用 localBuildToolsVersion:
android {
compileSdkVersion rootProject.ext.compileSdkVersion
//localBuildToolsVersion是gradle.properties中的數(shù)據(jù)
buildToolsVersion localBuildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode rootProject.ext.versionCode
versionName rootProject.ext.versionName
}
}
- 最后是最重要的一步,一定要將 gradle.properties 從版本控制工具(Git矫限、SVN)中給忽略掉哺哼,千萬不要把這個文件提交到代碼倉庫;然后把配置好的 gradle.properties 給每個開發(fā)人員發(fā)一份叼风,供他們本地使用取董,至于 gradle.properties 中的版本號隨便他們改好了,反正又不會傳到代碼倉庫无宿。