這篇文章我要向你介紹的是關於如何使用Gradle來更加優雅的管理多個module之間的依賴關係。java
相信你必定有這樣的經歷:主項目依賴於多個子項目,或者項目間互相依賴。不一樣子項目間的依賴的第三方庫版本又沒有進行統一,升級一個版本全部依賴的項目都要進行修改;甚至minSdkVersion與targetSdkVersion也不相同。android
今天咱們就來解決這個問題,讓Gradle版本管理更加優雅。git
以前的文章Android Gradle系列-運用篇中的dependencies使用的是最基本的引用方式。若是你有新建一個kotlin項目的經歷,那麼你將看到Google推薦的方案github
buildscript {
ext.kotlin_version = '1.1.51'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
複製代碼
在rootProject的build.gradle中使用ext來定義版本號全局變量。這樣咱們就能夠在module的build.gradle中直接引用這些定義的變量。引用方式以下:api
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
}
複製代碼
你能夠將這些變量理解爲java的靜態變量。經過這種方式可以達到不一樣module中的配置統一,但侷限性是,一但配置項過多,全部的配置都將寫到rootProject項目的build.gradle中,致使build.gradle臃腫。這不符合咱們的所提倡的模塊開發,因此應該想辦法將ext的配置單獨分離出來。app
這個時候我就要用到以前的文章Android Gradle系列-原理篇中所介紹的apply函數。以前的文章咱們只使用了apply三種狀況之一的plugin(應用一個插件,經過id或者class名),只使用在子項目的build.gradle中。maven
apply plugin: 'com.android.application'
複製代碼
此次咱們須要使用它的from,它主要是的做用是應用一個腳本文件。做用接下來咱們須要作的是將ext配置單獨放到一個gradle腳本文件中。函數
首先咱們在rootProject目錄下建立一個gradle腳本文件,我這裏取名爲version.gradle。gradle
而後咱們在version.gradle文件中使用ext來定義變量。例如以前的kotlin版本號就能夠使用以下方式實現ui
ext.deps = [:]
def versions = [:]
versions.support = "26.1.0"
versions.kotlin = "1.2.51"
versions.gradle = '3.2.1'
def support = [:]
support.app_compat = "com.android.support:appcompat-v7:$versions.support"
support.recyclerview = "com.android.support:recyclerview-v7:$versions.support"
deps.support = support
def kotlin = [:]
kotlin.kotlin_stdlib = "org.jetbrains.kotlin:kotlin-stdlib-jre7:$versions.kotlin"
kotlin.plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin"
deps.kotlin = kotlin
deps.gradle_plugin = "com.android.tools.build:gradle:$versions.gradle"
ext.deps = deps
def build_versions = [:]
build_versions.target_sdk = 26
build_versions.min_sdk = 16
build_versions.build_tools = "28.0.3"
ext.build_versions = build_versions
def addRepos(RepositoryHandler handler) {
handler.google()
handler.jcenter()
handler.maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
}
ext.addRepos = this.&addRepos
複製代碼
由於gradle使用的是groovy語言,因此以上都是groovy語法
例如kotlin版本控制,上面代碼的意思就是將有個kotlin相關的版本依賴放到deps的kotlin變量中,同時deps放到了ext中。其它的亦是如此。
既然定義好了,如今咱們開始引入到項目中,爲了讓全部的子項目都可以訪問到,咱們使用apply from將其引入到rootProject的build.gradle中
buildscript {
apply from: 'versions.gradle'
addRepos(repositories)
dependencies {
classpath deps.gradle_plugin
classpath deps.kotlin.plugin
}
}
複製代碼
這時build.gradle中就默認有了ext所聲明的變量,使用方式就如dependencies中的引用同樣。
咱們再看上面的addRepos方法,在關於Gradle原理的文章中已經分析了repositories會經過RepositoryHandler來執行,因此這裏咱們直接定義一個方法來統一調用RepositoryHandler。這樣咱們在build.gradle中就無需使用以下方式,直接調用addRepos方法便可
//以前調用
repositories {
google()
jcenter()
}
//如今調用
addRepos(repositories)
複製代碼
另外一方面,若是有多個module,例若有module1,如今就能夠直接在module1中的build.gradle中使用定義好的配置
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
// support
implementation deps.support.app_compat
//kotlin
implementation deps.kotlin.kotlin_stdlib
}
複製代碼
上面咱們還定義了sdk與tools版本,因此也能夠一塊兒統一使用,效果以下
android {
compileSdkVersion build_versions.target_sdk
buildToolsVersion build_versions.build_tools
defaultConfig {
applicationId "com.idisfkj.androidapianalysis"
minSdkVersion build_versions.min_sdk
targetSdkVersion build_versions.target_sdk
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
...
}
複製代碼
一旦實現了統一配置,那麼以後咱們要修改相關的版本就只需在咱們定義的version.gradle中修改便可。無需再對所用的module進行逐一修改與統一配置。
若是你的項目使用了kotlin,那麼buildSrc&Kotlin的統一管理方案將更適合你。
Gradle項目會默認識別buildSrc目錄,而且會將該目錄中的配置注入到build.gradle中,以致於讓build.gradle可以直接引用buildSrc中的配置項。
有了這一特性,咱們就能夠直接將以前version.gradle中的配置放入到buildSrc中,下面咱們開始實現。
首先在根目錄新建一個buildSrc目錄(與app同級),而後在該目錄新建src/main/java目錄,該目錄是你以後配置項所在的目錄;同時再新建build.gradle.kts文件,並在該文件中添加kotlin-dsl
plugins {
`kotlin-dsl`
}
repositories {
jcenter()
}
複製代碼
以後再sync project,最終的目錄結構以下
搭建好了目錄,如今咱們在src/main/java下使用kotlin新建Dependencies文件(文件名任意),在該文件中將以前的配置項放進來,只是使用kotlin語法進行實現而已,轉化的代碼以下
object Versions {
const val support = "26.1.0"
const val kotlin = "1.3.31"
const val gradle = "3.4.1"
const val target_sdk = 26
const val min_sdk = 16
const val build_tools = "28.0.3"
}
object Dependencies {
val app_compat = "com.android.support:appcompat-v7:${Versions.support}"
val kotlin_stdlib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${Versions.kotlin}"
val kotlin_plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlin}"
val gradle_plugin = "com.android.tools.build:gradle:${Versions.gradle}"
val addRepos: (handler: RepositoryHandler) -> Unit = {
it.google()
it.jcenter()
it.maven { url = URI("https://oss.sonatype.org/content/repositories/snapshots") }
}
}
複製代碼
這時你就能夠直接使用Dependencies與Versions在各個build.gradle中引用,例如app下的build.gradle
android {
compileSdkVersion Versions.target_sdk
buildToolsVersion Versions.build_tools
defaultConfig {
applicationId "com.idisfkj.androidapianalysis"
minSdkVersion Versions.min_sdk
targetSdkVersion Versions.target_sdk
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
...
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
// support
implementation Dependencies.app_compat
//kotlin
implementation Dependencies.kotlin_stdlib
}
複製代碼
根目錄的build.gradle亦是如此
buildscript {
Dependencies.addRepos.invoke(repositories)
dependencies {
classpath Dependencies.gradle_plugin
classpath Dependencies.kotlin_plugin
}
}
allprojects {
Dependencies.addRepos.invoke(repositories)
}
task clean(type: Delete) {
delete rootProject.buildDir
}
複製代碼
其實咱們真正須要get到的是一種思想,將配置統一管理。至於到底使用哪種,這就看我的喜愛了,但若是你的項目使用了kotlin,我仍是建議你使用buildSrc模式,由於對於Groovy語法而言,我相信你仍是對Kotlin更加熟悉。
源碼地址: github.com/idisfkj/and…
若是想了解更多關於個人文章,能夠掃描下方二維碼,關注個人公衆號~