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 做為依附元件。這個應用程式不會直接或間接使用 Library C。
圖 3. BOM 情境。

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

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