Auflösung der Gradle-Abhängigkeit

In Ihren Build-Dateien werden Ihre direkten Abhängigkeiten angegeben. Jede dieser Abhängigkeiten kann jedoch andere erfordern. Diese transitiven Abhängigkeiten führen schnell zu einem großen Abhängigkeitsdiagramm, oft mit in Konflikt stehenden Versionen.

Wenn sich die Teile minor (neue Funktionen) oder patch (Fehlerkorrekturen) ändern, ist die Bibliothek wahrscheinlich weiterhin kompatibel und hat weniger Auswirkungen auf Ihre Anwendung.

Angenommen, Ihre Anwendung ist von der Bibliothek A und der Bibliothek B abhängig, die wiederum von verschiedenen Versionen der Bibliothek C abhängen.

Ihre App hängt von Bibliothek A und Bibliothek B ab, die wiederum von verschiedenen Versionen der Bibliothek C abhängen. Gradle wählt die neueste Version der Bibliothek C aus.
Abbildung 1. Ein transitiver Versionskonflikt. Gradle löst standardmäßig die neueste Version auf.

In diesem Fall wählt Gradle standardmäßig die neueste Version der Bibliothek C aus, was zu Kompilierungs- oder Laufzeitproblemen führen kann. In diesem Beispiel wird Bibliothek C auf 2.1.1 aufgelöst. Beachten Sie jedoch, dass Bibliothek A Bibliothek C 1.0.3 angefordert hat. Der Großteil der Versionsnummer hat sich geändert. Dies weist auf inkompatible Änderungen wie entfernte Funktionen oder Typen hin. Dies kann dazu führen, dass Aufrufe aus Bibliothek A abstürzen.

Ihre App kann direkte Abhängigkeiten haben, die auch transitive Abhängigkeiten sind.

Ihre App hängt von Bibliothek A und Bibliothek C ab. Bibliothek A ist von einer neueren Version von Bibliothek C abhängig. Gradle wählt die neueste Version der Bibliothek C aus.
Abbildung 2: Ein anderer transitiver Versionskonflikt. Hier wird Gradle in die transitive Version aufgelöst und Ihre Anwendung erkennt diese neuere Version.

In einem solchen Fall können neuere transitive Abhängigkeiten die Version überschreiben, die Sie direkt in Ihrer App anfordern.

Gradle prüft alle Kandidatenversionen für alle Abhängigkeiten im Diagramm, um die neueste Version jeder Abhängigkeit zu ermitteln. Mit grundlegenden Gradle-Aufgaben und erweiterten Tools können Sie ermitteln, welche Versionen jeder Abhängigkeit Gradle behoben hat. Der Vergleich der Änderungen in dieser Auflösung ist entscheidend, um die Risiken des Upgrades zu verstehen und zu minimieren.

Sie können beispielsweise die Gradle-Aufgabe dependencies verwenden, indem Sie ./gradlew app:dependencies ausführen, um einen Baum aller Abhängigkeiten anzuzeigen, die von Ihrem App-Modul verwendet werden. Wenn wir diesen Befehl auf eine Anwendung anwenden, die die Bibliotheken wie in Abbildung 2 gezeigt verwendet, sehen wir

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 (*)

In diesem Teil des Berichts sind einige der Abhängigkeiten aufgeführt, die für die releaseRuntimeClasspath-Konfiguration behoben wurden.

Wenn Sie in Ihrem Abhängigkeitsbericht -> sehen, verwendet ein Anfragender (Ihre Anwendung oder eine andere Bibliothek) eine Version dieser Abhängigkeit, die nicht erwartet wird. In vielen Fällen verursacht dies keine Probleme, da die meisten Bibliotheken aus Gründen der Abwärtskompatibilität geschrieben werden. Einige Bibliotheken nehmen jedoch möglicherweise inkompatible Änderungen vor. Mithilfe dieses Berichts können Sie ermitteln, woher neue Probleme mit dem Verhalten Ihrer Anwendung kommen.

Weitere Informationen zur Verwendung der Abhängigkeitsberichte von Gradle finden Sie unter Abhängigkeiten ansehen und debuggen.

Sie können angeforderte Versionen direkt, in einem Versionskatalog oder in einer Stückliste angeben.

Auflösung der direkten Versionsspezifikation

Die von Ihnen angegebenen Versionen von Abhängigkeiten werden Kandidaten für die Versionsauflösung.

So fordern Sie beispielsweise Version 1.7.3 der androidx.compose.ui:ui-Bibliothek als Abhängigkeit in Ihrer app/build.gradle.kts an:

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

Version 1.7.3 wird zu einer Kandidatenversion. Gradle wird in der neuesten Version von 1.7.3 und anderen Versionen derselben Bibliothek aufgelöst, die von transitiven Abhängigkeiten angefordert werden.

Auflösung des Versionskatalogs

In Versionskatalogen werden Variablen definiert, um die Version der Abhängigkeiten zu erfassen, die in Ihrer Anwendung verwendet werden. Wenn Sie eine Variable aus dem Versionskatalog verwenden, werden die angegebenen Abhängigkeiten dieser Variablen den Kandidaten für die Versionsauflösung hinzugefügt. Nicht verwendete Variablen im Versionskatalog werden ignoriert.

So geben Sie beispielsweise Version 1.7.3 von androidx.compose.ui:ui als Abhängigkeit in Ihrer gradle/libs.versions.toml-Datei an:

[versions]
ui = "1.7.3"

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

Dadurch wird eine Variable namens libs.androidx.compose.ui für die Bibliothek definiert. Diese Version gilt nicht als Kandidaten, es sei denn, Sie verwenden diese Variable zum Angeben einer Abhängigkeit.

So fordern Sie die Bibliothek und ihre Version in Ihrer app/build.gradle.kts an:

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

Gradle wird auf dieselbe Weise aufgelöst wie bei einer direkten Spezifikation.

Auflösung der Stückliste

Versionen für alle Bibliotheken, die in der BOM aufgeführt sind, sind Kandidaten für die Versionsauflösung. Beachten Sie, dass Bibliotheken nur dann als Abhängigkeiten verwendet werden, wenn sie als direkt oder indirekt angegeben werden. Andere Bibliotheken in der BOM werden ignoriert.

BOM-Versionen wirken sich auf Ihre direkten Abhängigkeiten sowie alle transitiven Abhängigkeiten, die in der BOM angezeigt werden, aus.

Geben Sie beispielsweise eine BOM als Plattformabhängigkeit in Ihrer app/build.gradle.kts an:

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

Für alle Bibliotheken, die Sie als Abhängigkeiten verwenden möchten, ist keine Versionsspezifikation erforderlich. Die angeforderte Version stammt aus der BOM.

Sie können auch einen Versionskatalog verwenden, um Variablen für die BOM und die Bibliotheken zu erstellen. Lassen Sie die Versionsnummern im Versionskatalog für Bibliotheken weg, die in einer BOM-Abhängigkeit enthalten sind.

Angenommen, Ihr Versionskatalog enthält die BOM und ihre Versionsnummer, aber keine Version für die Bibliotheken, auf die Sie in der BOM verweisen:

[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 verweist mithilfe der im Versionskatalog definierten Variablen auf die BOM und die Bibliotheken:

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

Die in der BOM angegebene Version dieser Bibliothek wird als Kandidat für die Auflösung von Gradle ausgewählt. Darüber hinaus werden alle anderen in der BOM angegebenen Bibliotheksversionen zu Kandidatenversionen, unabhängig davon, ob Sie sie direkt als Abhängigkeiten verwenden.

Angenommen, in einer BOM werden Versionen für die Bibliotheken A, B und C angegeben. Ihre Anwendung möchte sowohl Bibliothek A als auch Bibliothek D direkt als Abhängigkeit verwenden. Bibliothek D verwendet Bibliothek B als Abhängigkeit. Bibliothek C wird von nichts verwendet.

Eine BOM enthält die Versionen für die Bibliotheken A, B und C. Ihre Anwendung verwendet die Bibliotheken A und D als Abhängigkeiten. Bibliothek D verwendet Bibliothek B als Abhängigkeit. Bibliothek C wird in dieser Anwendung weder direkt noch indirekt verwendet.
Abbildung 3 BOM-Szenario.

Die Bibliotheken A, B und D sind Abhängigkeiten in der Anwendung. Bibliothek C wird ignoriert. Gradle verwendet die in der BOM angegebenen Versionen von A und B als Kandidaten, auch wenn Sie Bibliothek B nicht direkt als Abhängigkeit angeben.

Wenn Bibliothek D eine Version von Bibliothek B anfordert, die niedriger als 2.0.1 ist, wird 2.0.1 von Gradle ermittelt. Wenn Bibliothek D eine höhere Version von Bibliothek B angefordert hat, wird Gradle auf diese Version aufgelöst.