Android Gradle 三方依賴管理詳解
發展歷史
Gradle 的依賴管理是一個從開始接觸 Android 開發就一直伴隨著我們的問題(作者是Android開發,僅以此為例),從最初的 沒有統一管理
到 通過.gradle或gradle.properties管理,再到 Kotlin 出現之後使用 buildSrc 管理
以及在這基礎上優化的 Composing Builds
,Gradle 依賴管理一直在不斷的發展、更新,而到瞭 Gradle 7.0,Gradle 本身又專門提供瞭全新的 Version Catalogs
用於依賴管理,今天我們就來說說這些方式的優劣及使用方式吧。
最原始的依賴
當我們通過 Android Studio 創建一個新項目,這個項目裡面默認的依賴就是最原始的,沒有經過統一管理的;如果你的項目中隻有一個 module
,那麼這種默認的管理方式也是可以接受的,是否對它進行優化,這取決於你是否願意投入成本去修改,談不上什麼優劣。
使用 .gradle 配置
當你的項目中 module
的數量超過一個甚至越來越多的時候,對 Gradle 依賴進行統一管理就變得重要起來,因為你不會想在升級一個三方依賴的版本後發現沖突,然後一個個打開各個 module
的 build.gradle
文件,找到你升級的那個依賴引用,重復的進行版本修改;
因此我們有瞭初步的優化方案:
- 在項目根目錄下創建
config.gradle
文件,在其中按照以下格式添加相關配置;
ext { android = [ compileSdkVersion: 30 ] dependencies = [ "androidx-core-ktx" : "androidx.core:core-ktx:1.3.2", "androidx-appcompat": "androidx.appcompat:appcompat:1.2.0", "google-material" : "com.google.android.material:material:1.3.0" ] }
- 在項目根目錄下的
build.gradle
文件頂部添加apply from: "config.gradle"
; - 在各個
module
的build.gradle
中就可以通過rootProject
來引用對應的依賴及參數瞭;
... android { compileSdkVersion rootProject.ext.android.compileSdkVersion } ... dependencies { implementation rootProject.ext.dependencies["androidx-core-ktx"] implementation rootProject.ext.dependencies["androidx-appcompat"] implementation rootProject.ext.dependencies["google-material"] } ...
使用這種方式,我們就能夠將項目中的版本配置、三方依賴統一管理起來瞭,但是這種方式還是有缺陷的,我們無法像正常代碼中一樣便捷的跳轉到依賴定義的地方,也不能簡單的找到定義的依賴在哪些地方被使用。
使用 gradle.properties 配置
這個方式和上面的方式類似,把依賴相關數據定義到 gradle.properties
文件中:
... androidx-core-ktx = androidx.core:core-ktx:1.3.2 androidx-appcompat = androidx.appcompat:appcompat:1.2.0 androidx-material = com.google.android.material:material:1.3.0
在各個 module
的 build.gradle
中使用;
... dependencies { implementation "${androidx-core-ktx}" implementation "${androidx-appcompat}" implementation "${google-material}" }
這種方式相對於 .gradle
方式不需要單獨創建 config.gradle
文件,但是同樣的也無法快速定位到定義的地方及快速跳轉到依賴使用。
使用 buildSrc 配置
在 Kotlin 的支持下,我們又有瞭新的方案,這個方案依賴於 IDEA 會將 buildSrc
路徑作為插件編譯到項目以及 Kotlin dsl 的支持,並且解決上面兩個方案依賴無法快速跳轉問題;
使用方式如下:
- 在項目根目錄新建文件夾
buildSrc
,並在該路徑下新建build.gradle.kts
文件,該文件使用 Kotlin 語言配置
repositories { google() mavenCentral() } plugins { // 使用 kotlin-dsl 插件 `kotlin-dsl` }
- 在
buildSrc
中添加源碼路徑src/main/kotlin
,並在源碼路徑下添加依賴配置Dependencies.kt
object Dependencies { const val ANDROIDX_CORE_KTX = "androidx.core:core-ktx:1.3.2" const val ANDROIDX_APPCOMPAT = "androidx.appcompat:appcompat:1.2.0" const val GOOGLE_MATERIAL = "com.google.android.material:material:1.3.0" }
- 在各個
module
中的build.gradle.kts
文件中使用依賴
... dependencies { implementation(Dependencies.ANDROIDX_CORE_KTX) implementation(Dependencies.ANDROIDX_APPCOMPAT) implementation(Dependencies.GOOGLE_MATERIAL) }
這個方案的優點正如上面所說的,能夠快速方便的定位到依賴的定義及使用,其確定就在於因為需要 Kotlin 支持,所以需要向項目中引入 Kotlin 的依賴,並且各個 module
的 build.gradle
配置文件需要轉換為 build.gradle.kts
格式。
使用 Composing Builds 配置
Composing Builds
方案的本質和 buildSrc
方案是一樣的,都是將對應 module
中的代碼編譯作為插件,在 build.gradle.kts
中可以直接引用,那為什麼還要有 Composing Builds
這種方案呢?這是因為 buildSrc
方案中,如果 buildSrc
中的配置有修改,會導致整個項目都會進行重新構建,如果項目較小可能影響不大,但如果項目過大,那這個缺點顯然是無法接受的,Composing Builds
方案應運而生。
使用方式:
- 在項目根目錄創建
module
文件夾,名稱隨意,這裡使用plugin-version
,並在文件夾中創建build.gradle.kts
配置文件,內容如下:
plugins { id("java-gradle-plugin") id("org.jetbrains.kotlin.jvm") version "1.7.10" } repositories { google() mavenCentral() gradlePluginPortal() } java { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } dependencies { // 添加Gradle相關的API,否則無法自定義Plugin和Task implementation(gradleApi()) implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10") } gradlePlugin { plugins { create("version") { // 添加插件,下面是包名 id = "xx.xx.xx" // 在源碼路徑創建類繼承 Plugin<Project> implementationClass = "xx.xx.xx.VersionPlugin" } } }
- 創建源碼目錄及包路徑
src/main/kotlin/xx.xx.xx
,在包中新建類VersionPlugin
繼承org.gradle.api.Plugin
class VersionPlugin : Plugin<Project> { override fun apply(target: Project) { } }
- 在項目根目錄下的
settings.gradle.kts
文件中添加includeBuild("plugin-version")
- 最後和
buildSrc
方案一樣,在源碼路徑下新增相關依賴配置,在各個module
中引用即可。
Version Catalogs 配置
從 Gradle 7.0
開始,Gradle
新增瞭 Version Catalogs
功能,用於在項目之間共享依賴項版本, Gradle
文檔中列出的一下優點:
- 對於每個
Catelog
,Gradle
都會生成類型安全的訪問器,可以輕松的在IDE
中使用,完成添加依賴; - 每個
Catelog
對生成的所有項目都可見,可以確保依賴版本同步到所有子項目; Catelog
可以聲明依賴關系包,這些捆綁包是通常在一起使用的依賴關系組;Catelog
可以將依賴項的組、名稱和實際版本分開,改用版本引用,從而可以在多個依賴項中共享版本聲明。
接下來我們來學習這種方案的具體使用。
開始使用
使用 Version Catalogs
首先當然是需要項目 Gradle
版本高於 7.0
,之後在項目根路徑下的 settings.gradle.kts
中添加配置(因為作者項目用的是 .kts
,groovy
按對應語法添加即可)
dependencyResolutionManagement { // 版本目錄配置 versionCatalogs { // 創建一個名稱為 libs 的版本目錄 create("libs") { // 聲明 groovy 依賴 library("groovy-core", "org.codehaus.groovy:groovy:3.0.5") } } }
在上面的配置之後,你就可以在項目中使用對應依賴瞭。例:build.gradle.kts
dependencies { implementation(libs.groovy.core) }
這裡有細心的小夥伴就會發現,我們聲明的是 groovy-core
,使用的時候卻是 libs.groovy.core
,這是因為 Version Catalogs
在根據別名生成依賴時對安全訪問器的映射要求,別名必須由 ascii
字符組成,後跟數字,中間分隔隻支持 短劃線-
、下劃線_
、點.
,因此聲明別名時可以使用groovy-core
、groovy_core
、groovy.core
,最終生成的都是 libs.groovy.core
。
使用 settings.gradle.kts 配置
就如上面的示例中,我們就是在 settings.gradle.kts
中聲明瞭 groovy-core
的依賴,並且需要的地方使用,接下來我們詳細說明對依賴項聲明的語法:
dependencyResolutionManagement { // 版本目錄配置 versionCatalogs { // 創建一個名稱為 libs 的版本目錄 create("libs") { // 聲明 kotlin 版本 version("kotlin", "1.7.10") // 聲明 groovy 版本 version("groovy", "3.0.5") // 聲明 groovy 依賴 library("groovy-core", "org.codehaus.groovy:groovy:3.0.5") // 聲明 groovy 依賴 library("groovy-nio", "org.codehaus.groovy", "groovy-nio").version("3.05") // 聲明 groovy 依賴使用版本引用 library("groovy-json", "org.codehaus.groovy", "groovy-json").versionRef("groovy") // 聲明 groovy 依賴組 bundle("groovy", listOf("groovy-core", "groovy-json", "groovy-nio")) // 聲明 kotlin 序列化插件 plugin("kotlin-serialization", "org.jetbrains.kotlin.plugin.serialization").versionRef("kotlin") } } }
這種方式相對統一瞭依賴版本,卻無法做到多項目統一。
使用 libs.versions.toml 配置
還是先看示例代碼:
dependencyResolutionManagement { // 版本目錄配置 versionCatalogs { // 創建一個名稱為 libs 的版本目錄 create("libs") { // 不能如此配置,會拋出異常 from(files("./gradle/libs.versions.toml")) // 可以添加此配置 from(files("./gradle/my-libs.versions.toml")) } // 創建一個名稱為 configLibs 的版本目錄 create("configLibs") { // 添加配置文件 from(files("./gradle/configLibs.versions.toml")) } } }
在配置版本目錄後,出瞭直接在 .kts
裡面添加依賴定義,還可以通過 from
方法從 .toml
文件中加載,.toml
文件一般放在項目根路徑下的 gradle
文件夾中。
這裡需要註意的是,gradle
有一個默認配置名稱為 libs
,如果你創建的版本目錄名稱是 libs
,那麼你就無需通過 from
方法加載 libs.versions.toml
文件,因為 gradle
會默認此配置,你隻需在 ./gradle
路徑下創建 libs.versions.toml
文件即可,重復添加會導致編譯失敗;如果你已經有瞭一個 libs.versions.toml
你也可以在添加以下配置來修改默認配置名稱:
dependencyResolutionManagement { defaultLibrariesExtensionName.set("projectLibs") }
如果你創建的版本目錄名稱不是默認配置名稱,那麼就需要你手動添加 from
方法加載配置;所有版本目錄名稱建議以 Libs
結尾,否則會有 warning
,提示後續將不支持此命名。
接下來我們來看 .toml
文件的配置規則:
# 聲明版本號 [versions] kotlin = "1.7.10" groovy = "3.0.5" # 聲明依賴 [libraries] # groovy groovy-core = "org.codehaus.groovy:groovy:3.0.5" groovy-json = { module = "org.codehaus.groovy:groovy-json", version = "3.0.5" } groovy-nio = { group = "org.codehaus.groovy", name = "groovy-nio", version.ref = "groovy" } # 聲明依賴組 [bundles] groovy = ["groovy-core", "groovy-json", "groovy-nio"] # 聲明插件 [plugins] kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
這種方式在統一單一項目依賴版本的同時,可以通過分享 .toml
文件來達成多項目依賴版本的統一,但是同樣的,同樣的文件在不同項目中不可避免是會被修改的,用著用著就不一致瞭。
使用插件配置
雖然從本地文件導入很方便,但是並不能解決多項目共享版本目錄的問題,gradle
提供瞭新的解決方案,我們可以在一個獨立的項目中配置好各個三方依賴,然後將其發佈到 maven
等三方倉庫中,各個項目再從 maven
倉庫中統一獲取依賴
插件配置
為瞭實現此功能,gradle
提供瞭 version-catalog
插件,再配合 maven-publish
插件,就能很方便的生產插件並發佈到 maven
倉庫。
新建 gradle
插件項目,修改 build.gradle.kts
plugins { `maven-publish` `version-catalog` } // 版本目錄配置 catalog { versionCatalog { // 在這裡配置各個三方依賴 from(files("./gradle/libs.versions.toml")) version("groovy", "3.0.5") library("groovy-json", "org.codehaus.groovy", "groovy-json").versionRef("groovy") } } // 配置 publishing publishing { publications { create<MavenPublication>("maven") { from(components["versionCatalog"]) } } }
這裡需要註意的是,插件項目的 gradle
版本必須要高於 7.0
並且低於使用該插件的項目的版本,否則將無法使用。
插件使用
配置從 maven
倉庫加載版本目錄
dependencyResolutionManagement { // 版本目錄配置 versionCatalogs { // 創建一個名稱為 libs 的版本目錄 create("libs") { // 從 maven 倉庫獲取依賴 from("io.github.wangjie0822:catalog:1.1.3") } } }
重寫版本
從 maven
倉庫中獲取版本目錄一般來講就不應該修改瞭,但是僅一份依賴清單怎麼滿足我們的開發需求呢,不說各個依賴庫都在不斷的持續更新,如果我們需要使用的依賴沒有在版本目錄裡面聲明呢?我們不可能為瞭修改一個依賴的版本或者添加一個依賴就頻繁的發佈Catalog
插件版本,這樣成本太高,這就需要我們進行個性化配置瞭
dependencyResolutionManagement { // 版本目錄配置 versionCatalogs { // 創建一個名稱為 libs 的版本目錄 create("libs") { // 從 maven 倉庫獲取依賴 from("io.github.wangjie0822:catalog:1.1.3") // 添加倉庫裡面沒有的依賴 library("tencent-mmkv", "com.tencent", "mmkv").version("1.2.14") // 修改groovy版本 version("groovy", "3.0.6") } } }
請註意,我們隻能重寫版本目錄裡面定義的版本號,所以在定義版本目錄時盡量將所有版本號都是用版本引用控制。
使用方式
上面說瞭那麼多的配置定義方式,下面來看看Version Catalogs
的使用方式:
plugins { // 可以直接使用定義的 version 版本號 kotlin("plugin.serialization") version libs.versions.kotlin // 也可以直接使用定義的插件 alias(libs.plugin.kotlin.serialization) } android { defaultConfig { // 其它非依賴的字段可以在版本目錄的版本中定義 通過 versions 獲取 minSdk = configLibs.versions.minSdk.get().toInt() targetSdk = configLibs.versions.targetSdk.get().toInt() versionCode = configLibs.versions.versionCode.get().toInt() versionName = configLibs.versions.versionName.get() } } dependencies { // 使用 groovy 依賴 implementation(libs.groovy.core) // 使用包含 groovy-core groovy-json groovy-no 三個依賴的依賴組 implementation(libs.bundles.groovy) // 使用 configLibs 中定義的依賴 implementation(configLibs.groovy.core) }
上面我們已經說過這種方案的優點,可以讓我們在所有項目中保持依賴版本的統一,甚至可以分享出去讓其他開發者使用;同時也有著和 buildSrc
、Composing Builds
一樣的可跳轉、可追溯的優點;
但是相比於這兩個方案,Version Catalogs
生成的代碼隻有默認的註釋,並且無法直接看到使用的依賴的版本號,而在 buildSrc
、Composing Builds
中我們能夠對依賴的功能進行詳細的註釋,甚至添加上對應的使用文檔地址、Github 地址等,如果支持自定義註釋,那這個功能就更完美瞭。
總結
Android 發展至今,各種新技術層出不窮,版本管理也出現瞭很多方案,這些方案並沒有絕對的優劣,還是需要結合實際項目需求來選擇的,但是新的方案還是需要學習瞭解的。
到此這篇關於Android Gradle 三方依賴管理詳解的文章就介紹到這瞭,更多相關Android Gradle內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 使用Composing builds提升Android編譯速度
- gradle和maven有哪些區別
- Android三方依賴沖突Gradle中exclude的使用
- Java中的Gradle與Groovy的區別及存在的關系
- windows下使用 intellij idea 編譯 kafka 源碼環境