Gradle 依存関係の解決

ビルドファイルでは直接的な依存関係を指定しますが、それぞれの依存関係で他の依存関係が必要になる場合があります。これらの推移的依存関係により、依存関係グラフ全体が急速に拡大し、多くの場合、バージョンが競合します。

minor(新機能)または patch(バグ修正)のパートが変更されても、ライブラリには引き続き互換性があり、アプリに影響を与える可能性が低くなります。

たとえば、アプリケーションがライブラリ A とライブラリ B に依存しており、さらに、この 2 つがライブラリ 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 が解決した各依存関係のバージョンを確認できます。この解像度での変更を比較することは、アップグレードのリスクを理解して軽減するうえで重要です。

たとえば、Gradle dependencies タスクを使用して ./gradlew app: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)で直接指定できます。

直接バージョンの仕様の解決

指定した依存関係のバージョンが、バージョン解決の候補になります。

たとえば、app/build.gradle.kts の依存関係として androidx.compose.ui:ui ライブラリのバージョン 1.7.3 をリクエストするには、次のようにします。

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 に表示されるすべての推移的依存関係に影響します。

たとえば、app/build.gradle.kts で BOM をプラットフォーム依存関係として指定します。

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 はそのバージョンに解決されます。