日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Android?Gradle?三方依賴管理詳解_Android

作者:王杰0822 ? 更新時間: 2022-10-07 編程語言

發展歷史

Gradle?的依賴管理是一個從開始接觸?Android?開發就一直伴隨著我們的問題(作者是Android開發,僅以此為例),從最初的?沒有統一管理?到?通過.gradle或gradle.properties管理,再到?Kotlin?出現之后使用?buildSrc 管理?以及在這基礎上優化的?Composing BuildsGradle?依賴管理一直在不斷的發展、更新,而到了?Gradle 7.0Gradle?本身又專門提供了全新的?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?中添加配置(因為作者項目用的是?.ktsgroovy?按對應語法添加即可)

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-coregroovy_coregroovy.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)
}

上面我們已經說過這種方案的優點,可以讓我們在所有項目中保持依賴版本的統一,甚至可以分享出去讓其他開發者使用;同時也有著和?buildSrcComposing Builds一樣的可跳轉、可追溯的優點;

但是相比于這兩個方案,Version Catalogs生成的代碼只有默認的注釋,并且無法直接看到使用的依賴的版本號,而在?buildSrcComposing Builds?中我們能夠對依賴的功能進行詳細的注釋,甚至添加上對應的使用文檔地址、Github 地址等,如果支持自定義注釋,那這個功能就更完美了。

總結

Android?發展至今,各種新技術層出不窮,版本管理也出現了很多方案,這些方案并沒有絕對的優劣,還是需要結合實際項目需求來選擇的,但是新的方案還是需要學習了解的。

原文鏈接:https://juejin.cn/post/7130530401763737607

欄目分類
最近更新