我的Github:https://github.com/BzCoder
本文基于MVPArms進行分析:https://github.com/JessYanCoding/MVPArms
歡迎各位留言討論
Gradle的管理在組件化改造中是一個非常有學問的環(huán)節(jié)。在我看來Gradle在其中的主要幾個職責:
- 引入包的版本管理
- 組件化編譯與總體編譯的切換
- 各模塊間的層級關系維護
- gradle.properties 配置中轉(zhuǎn)站
接下來我們就一點一點的講。
1.引入包的版本管理
這其實不是組件化開發(fā)的專利最疆。正如其他的項目一樣叹卷,統(tǒng)一的版本號我們都管理在Config.gradle中赁项。類似下面的文件然想。在模塊中引入模塊時,統(tǒng)一通過類似api rootProject.ext.dependencies["mmkv"]
的引入方式來保證版本的統(tǒng)一询吴。這個很好理解齿尽,因為都是常規(guī)操作沽损。
ext {
android = [
applicationId : "${PACKAGE_NAME}",
compileSdkVersion: 28,
buildToolsVersion: "28.0.3",
minSdkVersion : 18,
targetSdkVersion : 28,
versionCode : VERSION_CODE as int,
versionName : "${VERSION_NAME}"
]
version = [
androidSupportSdkVersion: "28.0.0",
retrofitSdkVersion : "2.4.0",
dagger2SdkVersion : "2.19",
]
dependencies = [
//support
"appcompat-v7" : "com.android.support:appcompat-v7:${version["androidSupportSdkVersion"]}",
"design" : "com.android.support:design:${version["androidSupportSdkVersion"]}",
"support-v4" : "com.android.support:support-v4:${version["androidSupportSdkVersion"]}",
"cardview-v7" : "com.android.support:cardview-v7:${version["androidSupportSdkVersion"]}",
"annotations" : "com.android.support:support-annotations:${version["androidSupportSdkVersion"]}",
"recyclerview-v7" : "com.android.support:recyclerview-v7:${version["androidSupportSdkVersion"]}",
"constraint-layout" : 'com.android.support.constraint:constraint-layout:1.1.3',
]
defaultConfig {
minSdkVersion rootProject.ext.android["minSdkVersion"]
targetSdkVersion rootProject.ext.android["targetSdkVersion"]
versionCode rootProject.ext.android["versionCode"]
versionName rootProject.ext.android["versionName"]
testInstrumentationRunner rootProject.ext.dependencies["androidJUnitRunner"]
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
includeCompileClasspath true
}
}
multiDexEnabled true
}
2.組件化編譯與總體編譯的切換
2.1 App與Lib
我們知道,lib模塊需要引入apply plugin: 'com.android.library'
循头,應用模塊引入apply plugin: 'com.android.application'
绵估,而在組件化開發(fā)中炎疆,這兩種狀態(tài)是要不斷地切換的,所以我們可以在gradle.properties設定參數(shù)isBuildModule來控制国裳。于是gradle的頭部就變成了以下
if (isBuildModule.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
當然在實際開發(fā)中我們設計了多層形入,相應的我們也給每層建立了基礎gradle,參數(shù)也隨之變成了isBuildModuleOne缝左,isBuildModuleTwo亿遂,isBuildModuleThree...每一層的業(yè)務只要依賴該層基礎gradle即可。
2.2 兩套Manifest
組件化編譯和整體編譯渺杉,他們的清單文件也是不同的蛇数。我們通過在Gradle中android節(jié)點中加入以下代碼來控制工程使用兩套Manifest,但是這種方案美中不足的是是越,你的每個Activity的注冊都必須要寫兩次耳舅,否則切換編譯模式后,會出現(xiàn)錯誤倚评,有待改進浦徊。
sourceSets {
main {
jniLibs.srcDirs = ['libs']
if (isBuildModule.toBoolean()) {
manifest.srcFile 'src/main/debug/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/release/AndroidManifest.xml'
}
}
}
2.3 不同編譯方式時導入不同的包
說到包的導入,我們先必須明確兩個關鍵字的概念蔓纠。
- runtimeOnly:只有在運行時才編譯辑畦。
- compileOnly:只有編譯的時候引入吗蚌,實際打包時并不會加入到包當中腿倚。
根據(jù)以上原則
在模塊互相導入時,我們使用如下格式:
if (isBuildModule.toBoolean()) {
if (moduleXX.toBoolean()) {
runtimeOnly project(":moduleXX")
}
}
這樣寫蚯妇,首先(if語句)可以通過配置文件來確認某個模塊是否加入敷燎,使用runtimeOnly ,可以在某一個Module組件化編譯時箩言,不會影響其他引用它的模塊硬贯。還有一點,我們在引用的外層包裹了一層是否為組件化編譯的狀態(tài)判斷(isBuildModule)陨收,這是為了防止模塊的重復引入饭豹。因為在組件化開發(fā)時,模塊之間是不需要互相顯式引用的务漩,我們最終的模塊引用是通過APP引用的拄衰。
在通用模塊導入時,我們使用如下格式:
butterknife饵骨,dagger2等包引入翘悉。
if (isBuildModule.toBoolean()) {
//view
annotationProcessor(rootProject.ext.dependencies["butterknife-compiler"]) {
exclude module: 'support-annotations'
}
//tools
annotationProcessor rootProject.ext.dependencies["dagger2-compiler"]
annotationProcessor rootProject.ext.dependencies["arouter-compiler"]
//test
debugImplementation rootProject.ext.dependencies["canary-debug"]
releaseImplementation rootProject.ext.dependencies["canary-release"]
testImplementation rootProject.ext.dependencies["canary-release"]
} else {
compileOnly rootProject.ext.dependencies["butterknife-compiler"]
compileOnly rootProject.ext.dependencies["dagger2-compiler"]
compileOnly rootProject.ext.dependencies["arouter-compiler"]
compileOnly rootProject.ext.dependencies["canary-debug"]
compileOnly rootProject.ext.dependencies["canary-release"]
}
這樣寫只有在組件化編譯的時候,模塊才會真正把基礎包引入居触,整體打包時妖混,只有一份老赤。
3.Manifest與gradle.properties的數(shù)據(jù)橋梁
因為我們目標想把所有的配置文件都整合到gradle.properties中,但是manifest又不能直接調(diào)用gradle.properties中的參數(shù)制市,我們就必須借助gradle作為“中間人”抬旺。我們在gradle的defaultconfig節(jié)點中加入(以下為推送的寫法)
manifestPlaceholders = [
GETUI_APP_ID : "${PUSH_APPID}",
GETUI_APP_KEY : "${PUSH_APPKEY}",
GETUI_APP_SECRET: "${PUSH_APPSECRET}"
]
這樣一來,在Manifest中就可以取到gradle.properties 的參數(shù)了息堂。
總結(jié)
Gradle配置總的來說不是太難嚷狞,以上方案也存在可以優(yōu)化的地方,就是Manifest荣堰,攜程曾經(jīng)有一篇文件是利用manifest的tools:node ="remove"來進行manifest的合并床未,但是很可惜,在我自己實踐的過程中振坚,遇到了不少困難薇搁,最終沒有采用攜程的方案。好的渡八,那么今天的文章就先暫時寫到這里啃洋。