Fehler bei der Behebung von Abhängigkeitsabhängigkeiten beheben

Wenn Sie eine Abhängigkeit hinzufügen, können Probleme mit Abhängigkeiten auftreten, die für die ursprüngliche Abhängigkeit erforderlich sind, und Konflikte zwischen verschiedenen Abhängigkeitsversionen. Im Folgenden wird beschrieben, wie Sie Ihr Abhängigkeitsdiagramm analysieren und häufige Probleme beheben.

Eine Anleitung zum Beheben von Fehlern bei der Abhängigkeitsauflösung, die eine benutzerdefinierte Build-Logik beinhalten, finden Sie unter Benutzerdefinierte Strategien zur Abhängigkeitsauflösung.

Modulabhängigkeiten ansehen

Einige direkte Abhängigkeiten können eigene Abhängigkeiten haben. Diese werden als transitive Abhängigkeiten bezeichnet. Sie müssen nicht jede vorübergehende Abhängigkeit manuell deklarieren. Gradle erfasst sie automatisch und fügt sie für Sie hinzu. Das Android-Plug-in für Gradle bietet eine Aufgabe, die eine Liste der Abhängigkeiten anzeigt, die Gradle für ein bestimmtes Modul löst.

Für jedes Modul werden im Bericht außerdem die Abhängigkeiten nach Build-Variante, Testquellsatz und Klassenpfad gruppiert. Im folgenden Beispielbericht sehen Sie den Laufzeitklassenpfad eines Anwendungsmoduls seiner Debug-Build-Variante und den Kompilierungsklassenpfad seines instrumentierten Testquellsatzes.

debugRuntimeClasspath - Dependencies for runtime/packaging
+--- :mylibrary (variant: debug)
+--- com.google.android.material:material:1.0.0@aar
+--- androidx.appcompat:appcompat:1.0.2@aar
+--- androidx.constraintlayout:constraintlayout:1.1.3@aar
+--- androidx.fragment:fragment:1.0.0@aar
+--- androidx.vectordrawable:vectordrawable-animated:1.0.0@aar
+--- androidx.recyclerview:recyclerview:1.0.0@aar
+--- androidx.legacy:legacy-support-core-ui:1.0.0@aar
...

debugAndroidTest
debugAndroidTestCompileClasspath - Dependencies for compilation
+--- androidx.test.ext:junit:1.1.0@aar
+--- androidx.test.espresso:espresso-core:3.1.1@aar
+--- androidx.test:runner:1.1.1@aar
+--- junit:junit:4.12@jar
...

So führen Sie die Task aus:

  1. Wählen Sie View > Tool Windows > Gradle (Ansicht > Tool-Fenster > Gradle) aus oder klicken Sie in der Symbolleiste des Tool-Fensters auf Gradle .
  2. Maximieren Sie AppName > Tasks > android und klicken Sie doppelt auf androidDependencies. Nachdem Gradle die Aufgabe ausgeführt hat, sollte das Fenster Ausführen geöffnet werden. Dort wird die Ausgabe angezeigt.

Weitere Informationen zum Verwalten von Abhängigkeiten in Gradle finden Sie unter Grundlagen der Abhängigkeitsverwaltung im Gradle-Nutzerhandbuch.

Transitive Abhängigkeiten ausschließen

Wenn der Umfang einer Anwendung zunimmt, kann sie eine Reihe von Abhängigkeiten enthalten, einschließlich direkter und transitiver Abhängigkeiten (Bibliotheken, von denen die importierten Bibliotheken Ihrer Anwendung abhängig sind). Mit dem Schlüsselwort exclude können Sie so vorübergehende Abhängigkeiten ausschließen, die Sie nicht mehr benötigen:

Kotlin

dependencies {
    implementation("some-library") {
        exclude(group = "com.example.imgtools", module = "native")
    }
}

Groovig

dependencies {
    implementation('some-library') {
        exclude group: 'com.example.imgtools', module: 'native'
    }
}

Transitive Abhängigkeiten von Testkonfigurationen ausschließen

Wenn Sie bestimmte Transitive Abhängigkeiten aus Ihren Tests ausschließen müssen, funktioniert das oben gezeigte Codebeispiel möglicherweise nicht wie erwartet. Das liegt daran, dass eine Testkonfiguration (z.B. androidTestImplementation) erweitert die implementation-Konfiguration des Moduls. Das heißt, sie enthält immer implementation-Abhängigkeiten, wenn Gradle die Konfiguration auflöst.

Wenn Sie vorübergehende Abhängigkeiten aus Ihren Tests ausschließen möchten, müssen Sie dies bei der Ausführung wie unten gezeigt tun:

Kotlin

android.testVariants.all {
    compileConfiguration.exclude(group = "com.jakewharton.threetenabp", module = "threetenabp")
    runtimeConfiguration.exclude(group = "com.jakewharton.threetenabp", module = "threetenabp")
}

Groovig

android.testVariants.all { variant ->
    variant.getCompileConfiguration().exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp'
    variant.getRuntimeConfiguration().exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp'
}

Hinweis:Sie können weiterhin das Schlüsselwort exclude im Abhängigkeitenblock verwenden, wie im ursprünglichen Codebeispiel im Abschnitt Transitive Abhängigkeiten ausschließen beschrieben, um vorübergehende Abhängigkeiten auszulassen, die für die Testkonfiguration spezifisch sind und nicht in anderen Konfigurationen enthalten sind.

Fehler bei der Abhängigkeitsauflösung beheben

Wenn Sie Ihrem Anwendungsprojekt mehrere Abhängigkeiten hinzufügen, können diese direkten und vorübergehenden Abhängigkeiten miteinander in Konflikt stehen. Das Android-Gradle-Plug-in versucht, diese Konflikte ordnungsgemäß zu lösen. Einige Konflikte können jedoch zu Kompilierungszeit- oder Laufzeitfehlern führen.

Damit Sie besser nachvollziehen können, welche Abhängigkeiten zu Fehlern führen, prüfen Sie die Abhängigkeitsstruktur Ihrer Anwendung und suchen Sie nach Abhängigkeiten, die mehr als einmal oder mit in Konflikt stehenden Versionen vorkommen.

Wenn Sie die Abhängigkeit doppelt finden können, suchen Sie über die Benutzeroberfläche von Android Studio nach Abhängigkeiten, die die doppelte Klasse enthalten:

  1. Wählen Sie in der Menüleiste Navigation > Kurs aus.
  2. Achten Sie darauf, dass im Dialogfeld für die Pop-up-Suche das Kästchen neben Elemente, die nicht zum Projekt gehören angeklickt ist.
  3. Geben Sie den Namen der Klasse ein, die im Build-Fehler angezeigt wird.
  4. Überprüfen Sie die Ergebnisse für die Abhängigkeiten, die die Klasse enthalten.

In den folgenden Abschnitten werden die verschiedenen Arten von Fehlern bei der Abhängigkeitsauflösung und deren Behebung beschrieben.

Fehler aufgrund doppelter Kurse beheben

Wenn eine Klasse im Laufzeitklassenpfad mehrmals vorhanden ist, erhalten Sie eine Fehlermeldung wie diese:

Program type already present com.example.MyClass

Dieser Fehler tritt normalerweise aus einem der folgenden Umstände auf:

  • Eine binäre Abhängigkeit umfasst eine Bibliothek, die Ihre Anwendung ebenfalls als direkte Abhängigkeit einschließt. Beispiel: Ihre Anwendung deklariert eine direkte Abhängigkeit von Bibliothek A und Bibliothek B, aber Bibliothek A enthält bereits Bibliothek B in ihrer Binärdatei.
    • Um dieses Problem zu beheben, entfernen Sie Bibliothek B als direkte Abhängigkeit.
  • Ihre Anwendung hat eine lokale binäre Abhängigkeit und eine Remote-Binärabhängigkeit von derselben Bibliothek.
    • Um dieses Problem zu beheben, entfernen Sie eine der binären Abhängigkeiten.

Konflikte zwischen Klassenpfaden beheben

Wenn Gradle den Kompilierungsklassenpfad auflöst, löst er zuerst den Klassenpfad runtime auf und bestimmt anhand des Ergebnisses, welche Versionen der Abhängigkeiten dem Kompilierungsklassenpfad hinzugefügt werden sollen. Mit anderen Worten, der Laufzeitklassenpfad bestimmt die erforderlichen Versionsnummern für identische Abhängigkeiten von nachgelagerten Klassenpfaden.

Der Laufzeitklassenpfad Ihrer App bestimmt auch die Versionsnummern, die Gradle zum Abgleich von Abhängigkeiten im Laufzeitklassenpfad für das Test-APK der App benötigt. Die Hierarchie der Klassenpfade wird in Abbildung 1 beschrieben.

Abbildung 1: Versionsnummern von Abhängigkeiten, die über mehrere Klassenpfade hinweg vorkommen, müssen gemäß dieser Hierarchie übereinstimmen.

Ein Konflikt, bei dem verschiedene Versionen derselben Abhängigkeit über mehrere Klassenpfade hinweg angezeigt werden, kann beispielsweise dann auftreten, wenn Ihre Anwendung eine Version einer Abhängigkeit mithilfe der Abhängigkeitskonfiguration implementation enthält und ein Bibliotheksmodul eine andere Version der Abhängigkeit mithilfe der runtimeOnly-Konfiguration enthält.

Beim Auflösen von Abhängigkeiten von Ihrer Laufzeit und zum Kompilieren von Zeitklassenpfaden versucht das Android-Gradle-Plug-in 3.3.0 und höher, bestimmte nachgelagerte Versionskonflikte automatisch zu beheben. Wenn der Laufzeitklassenpfad beispielsweise Bibliothek A Version 2.0 und der Kompilierungsklassenpfad Bibliothek A Version 1.0 enthält, aktualisiert das Plug-in die Abhängigkeit vom Kompilierungsklassenpfad automatisch auf Bibliothek A Version 2.0, um Fehler zu vermeiden.

Wenn der Laufzeitklassenpfad jedoch Bibliothek A Version 1.0 und der Kompilierungsklassenpfad Bibliothek A Version 2.0 enthält, führt das Plug-in keine Downgrades der Abhängigkeit vom Kompilierungsklassenpfad auf Bibliothek A Version 1.0 durch und Sie erhalten weiterhin einen Fehler wie der folgende:

Conflict with dependency 'com.example.library:some-lib:2.0' in project 'my-library'.
Resolved versions for runtime classpath (1.0) and compile classpath (2.0) differ.

Führen Sie einen der folgenden Schritte aus, um das Problem zu beheben:

  • Fügen Sie die gewünschte Version der Abhängigkeit als api-Abhängigkeit in Ihr Bibliotheksmodul ein. Das heißt, nur Ihr Bibliotheksmodul deklariert die Abhängigkeit, das Anwendungsmodul hat jedoch vorübergehend auch Zugriff auf seine API.
  • Alternativ können Sie die Abhängigkeit in beiden Modulen deklarieren. Achten Sie aber darauf, dass jedes Modul dieselbe Version der Abhängigkeit verwendet. Konfigurieren Sie projektweite Attribute, damit die Versionen jeder Abhängigkeit im gesamten Projekt konsistent bleiben.