Gradle 依附元件解析

建構檔案會指定「直接」依附元件,但每個依附元件都可能需要其他依附元件。這些傳遞依附元件會迅速擴大整體依附元件圖表,且通常會出現版本衝突。

minor (新功能) 或 patch (錯誤修正) 部分變更時,程式庫仍可能與程式庫相容,且較不可能影響應用程式。

舉例來說,假設您的應用程式依附程式庫 A 和程式庫 B,而這兩者又依附不同版本的程式庫 C。

應用程式依附程式庫 A 和程式庫 B,後者依附程式庫 C 的不同版本。Gradle 會選擇最新版本的程式庫 C。
圖 1. 傳遞版本衝突。Gradle 會解析為最新版本 (預設)。

在這種情況下,Gradle 會預設選擇最新版本的程式庫 C,這可能會導致編譯或執行階段問題。在這個範例中,程式庫 C 會解析為 2.1.1,但請注意,程式庫 A 要求程式庫 C 1.0.3。版本號碼的主要部分已變更,表示出現不相容的變更,例如已移除的函式或類型。這可能會導致從程式庫 A 發出的呼叫發生當機。

您的應用程式可以有直接依附元件,這些依附元件同時也是遞移依附元件。

您的應用程式依附於程式庫 A 和程式庫 C。程式庫 A 依附於新版程式庫 C。Gradle 會選擇程式庫 C 的最新版本。
圖 2. 其他遞移版本衝突。在這裡,Gradle 會解析為傳遞版本,而應用程式會看到較新的版本。

在這種情況下,較新的遞移依附元件可以覆寫您在應用程式中直接要求的版本。

Gradle 會查看圖表中所有依附元件的所有候選版本,藉此判斷每個依附元件的最新版本。您可以使用基本 Gradle 工作更進階的工具來判斷各個依附元件 Gradle 已解析的版本。比較這種解析度的變更後,是瞭解並降低升級風險的關鍵。

舉例來說,您可以執行 ./gradlew app:dependencies 來使用 Gradle dependencies 工作,以便顯示應用程式模組所使用的所有依附元件樹狀圖。針對使用程式庫的應用程式執行此操作 (如圖 2 所示),我們會看到

1: releaseRuntimeClasspath - Runtime classpath of /release.
2: +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0
3: |    +--- ... (omitted for brevity) ...
4: +--- com.sample:library.a:1.2.3
5: |    +--- com.sample:library.c:2.1.1
6: |    |    \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 (*)
7: |    \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 (*)
8: +--- com.sample:library.c:1.4.1 -> 2.1.1 (*)

報表的這個部分說明已針對 releaseRuntimeClasspath 設定解析的部分依附元件。

只要依附元件報表中出現 ->,要求者 (您的應用程式或其他程式庫) 就會使用非預期的依附元件版本。在許多情況下,這不會造成任何問題,因為大多數程式庫都是為了回溯相容性而編寫。不過,部分程式庫可能會有不相容的變更,而這份報表可協助您判斷應用程式行為的新問題來源。

如要進一步瞭解如何使用 Gradle 的依附元件回報功能,請參閱「檢視及偵錯依附元件」一文。

您可以在版本目錄或物料清單 (BOM) 中,直接指定要求的版本。

直接版本規格解析

您指定的依附元件版本會成為版本解析的候選版本。

舉例來說,如要要求 androidx.compose.ui:ui 程式庫 1.7.3 版做為 app/build.gradle.kts 中的依附元件:

dependencies {
    implementation("androidx.compose.ui:ui:1.7.3")
}

版本 1.7.3 會成為候選版本。Gradle 會將 1.7.3 和其他版本的相同程式庫解析為最新版本,這些版本是由間接依附元件要求。

版本目錄解析

版本目錄會定義變數,以追蹤應用程式中使用的依附元件版本。如果您使用版本目錄中的變數,系統會將該變數指定的依附元件加入候選版本,以進行版本解析。系統會忽略版本目錄中未使用的變數。

舉例來說,如要在 gradle/libs.versions.toml 檔案中將 androidx.compose.ui:ui 的 1.7.3 版本指定為依附元件:

[versions]
ui = "1.7.3"

[libraries]
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui", version.ref = "ui" }

這會定義名為 libs.androidx.compose.ui 的變數,用來代表程式庫。除非您使用該變數指定依附元件,否則系統「不會」將這個版本視為候選版本。

如要在 app/build.gradle.kts 中要求程式庫及其版本:

dependencies {
    implementation(libs.androidx.compose.ui)
}

Gradle 解析的方式與直接規格相同。

物料清單 (BoM) 解析度

BOM 中顯示的所有程式庫版本都會成為版本解析的候選項目。請注意,只有在指定為直接或間接時,程式庫才會用做依附元件。系統會忽略 BOM 中的其他程式庫。

BOM 版本會影響直接依附元件,以及 BOM 中顯示的所有傳遞依附元件。

舉例來說,您可以將 BOM 指定為 app/build.gradle.kts 中的平台依附元件:

dependencies {
    implementation(platform("androidx.compose:compose-bom:2024.10.00"))
    implementation("androidx.compose.ui:ui")
}

您要用來做為依附元件的任何程式庫都不需要版本規格;所要求的版本會來自 BOM。

請注意,您也可以使用版本目錄為 BOM 和程式庫建立變數。針對 BOM 依附元件中顯示的程式庫,在版本目錄中省略版本號碼。

例如,版本目錄包含 BOM 及其版本號碼,但不指定您從 BOM 參照的程式庫版本:

[versions]
composeBom = "2024.10.00"

[libraries]
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }

app/build.gradle.kts 會使用版本目錄中定義的變數參照 BOM 和程式庫:

dependencies {
    implementation(platform(libs.androidx.compose.bom))
    implementation(libs.androidx.compose.ui)
}

BOM 中指定的程式庫版本成為 Gradle 解決方案的候選版本。此外,無論您是否直接使用這些版本做為依附元件,BOM 中指定的所有其他程式庫版本都會成為候選版本。

舉例來說,假設 BOM 指定程式庫 A、B 和 C 的版本。您的應用程式想要直接使用程式庫 A 和程式庫 D 做為依附元件。程式庫 D 使用程式庫 B 做為依附元件。不使用程式庫 C。

BOM 包含程式庫 A、B 和 C 的版本。應用程式使用程式庫 A 和 D 做為依附元件。程式庫 D 使用程式庫 B 做為依附元件。這個應用程式不會直接或間接使用 C 程式庫。
圖 3.BOM 情境。

程式庫 A、B 和 D 是應用程式中的依附元件;系統會忽略程式庫 C。即使您未直接將程式庫 B 指定為依附元件,Gradle 仍會使用 BOM 中指定的 A 和 B 版本做為候選項目。

如果程式庫 D 要求的程式庫 B 版本低於 2.0.1,Gradle 會解析為 2.0.1。如果程式庫 D 要求較高版本的程式庫 B,Gradle 會解析至該版本。