Auflösung von SDK-Abhängigkeiten für Android

Abhängigkeitsprobleme treten auf, wenn gemeinsam verwendete Pakete oder Bibliotheken von mehreren anderen Paketen benötigt werden, diese Pakete jedoch unterschiedliche und miteinander inkompatible Versionen der gemeinsam verwendeten Pakete benötigen. Gradle hat das Leben von Android-Entwickler*innen deutlich vereinfacht. Es genügt, eine Abhängigkeit in build.gradle anzugeben, und die erforderliche Bibliothek wird nahtlos in den Build integriert. Aber was passiert, wenn zwei Abhängigkeiten von unterschiedlichen Versionen derselben Bibliothek abhängen?

Gradle kann Abhängigkeiten automatisch auflösen, wenn beide Abhängigkeiten zur gleichen Konfiguration gehören, z. B. zur App-Konfiguration. Das Audience Network-SDK für Android hängt beispielsweise von der Bibliothek exoplayer ab. Wenn du eine andere Version der Bibliothek exoplayer hinzufügen möchtest, wählt Gradle die höhere Version aus. Wenn die Abhängigkeiten jedoch zu unterschiedlichen Konfigurationen gehören, z. B. App und Test, dann löst Gradle einen Fehler aus. Hier findest du eine Liste der möglichen Konflikte und Lösungsansätze.

Voraussetzungen

Stelle sicher, dass du die Leitfäden zu den ersten Schritten mit dem Audience Network und mit Android abgeschlossen hast, bevor du fortfährst.

Abhängigkeitskonflikte

1: Gemeinsam verwendete Bibliotheken in Abhängigkeiten aus der gleichen Konfiguration

2: Gemeinsam verwendete Bibliotheken in Abhängigkeiten aus unterschiedlichen Konfigurationen

Auflösen von Abhängigkeitskonflikten

1: Gradle löst deine Abhängigkeiten auf

2: Ausschließen einer bestimmten Version der Abhängigkeit

3: Definieren der entsprechenden Bibliothek explizit in Gradle

4: Erzwingen der Auflösung der Bibliothek



Abhängigkeitskonflikte

1: Gemeinsam verwendete Bibliotheken in Abhängigkeiten aus der gleichen Konfiguration

Betrachte das folgende Beispiel. Beide Abhängigkeiten im folgenden Code befinden sich in der gleichen Konfiguration und hängen intern von der Bibliothek "org.hamcrest:hamcrest-core" ab. Da die Abhängigkeiten intern unterschiedliche Versionen derselben Bibliothek verwenden, wird die höchste Version in den Build integriert. In der Ausgabe der Cradle-Synchronisierung wird deutlich darauf hingewiesen, dass die Version der Bibliothek hamcrest im endgültigen Build automatisch von 1.1 auf 1.3 angehoben wurde.

// Depends on version 1.3 of org.hamcrest:hamcrest-core
androidTestImplementation 'junit:junit:4.12' 
// Depends on version 1.1 of org.hamcrest:hamcrest-core
androidTestImplementation 'org.mockito:mockito-core:1.10.19'  

2: Gemeinsam verwendete Bibliotheken in Abhängigkeiten aus unterschiedlichen Konfigurationen

Wenn die Abhängigkeiten jedoch zu unterschiedlichen Konfigurationen gehören, z. B. App und Test, dann löst Gradle einen Fehler aus. Betrachte den folgenden Code-Ausschnitt. Die erste Abhängigkeit gehört zur App-Konfiguration, und die zweite Abhängigkeit gehört zur Test-Konfiguration. Daher schlägt die Erstellung des Projekts mit einer Ausnahme fehl.

Bei Messungstests verwenden Haupt- und Test-APK jeweils denselben Classpath. Der Gradle-Build schlägt fehl, wenn Haupt- und Test-APK unterschiedliche Versionen derselben Bibliothek (z. B. Guava) verwenden. Wenn Gradle diese Situation nicht behebt, kann es passieren, dass sich deine App in Tests anders verhält als im Normalzustand (inklusive Abstürze in einem der Fälle).

// Depends on version 1.3 of org.hamcrest:hamcrest-core 
implementation 'junit:junit:4.12' 
// Depends on version 1.1 of org.hamcrest:hamcrest-core
androidTestImplementation 'org.mockito:mockito-core:1.10.19' 

Auflösen von Abhängigkeitskonflikten

1: Gradle löst deine Abhängigkeiten auf

Dieser Ansatz ist einfach, gilt jedoch nur für Abhängigkeiten in der gleichen Konfiguration. Angenommen, dein Modul hängt explizit von einer bestimmten Version von ExoPlayer ab. Das Audience Network-SDK hat jedoch bereits eine andere Version von ExoPlayer eingebunden. Standardmäßig wird die höchste Version in den Build eingebunden. Mit dem folgenden Code-Ausschnitt wird in der Ausgabe der Cradle-Synchronisierung deutlich darauf hingewiesen, dass die Version der Bibliothek ExoPlayer im endgültigen Build automatisch von r2.4.2 auf 2.7.3 angehoben wurde.

implementation 'com.google.android.exoplayer:exoplayer-core:2.7.3'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.7.3'
...
// audience-network-sdk depends on exoplayer-core:r2.4.2 and exoplayer-dash:r2.4.2
implementation 'com.facebook.android:audience-network-sdk:4.28.1' 

2: Ausschließen einer bestimmten Version der Abhängigkeit

Normalerweise möchten Entwickler*innen selbst festlegen, welche Version der Bibliothek in den endgültigen Build eingebunden wird. Zu diesem Zweck kannst du build.gradle konfigurieren. Wenn dein*e Entwickler*in beispielsweise die niedrigere Version ExoPlayer r2.4.0 anstelle von r2.4.2 im Audience Network-SDK bevorzugt, kannst du dieses Modul beim Deklarieren der Abhängigkeit audience-network-sdk ausschließen. Das Ausschließen-Tag gilt auch für Abhängigkeiten in anderen Konfigurationen.

In der Praxis haben Projekte zahlreiche Abhängigkeiten von unterschiedlichen Versionen derselben Bibliothek. In diesem Fall musst du für jede einzelne Abhängigkeit ein Ausschließen-Tag festlegen, um die erwartete Version der jeweiligen Bibliothek einbinden zu können.

Szenario 1: Abhängigkeiten in der gleichen Konfiguration
implementation 'com.google.android.exoplayer:exoplayer-core:r2.4.0'
implementation 'com.google.android.exoplayer:exoplayer-dash:r2.4.0'
...
// audience-network-sdk depends on exoplayer-core:r2.4.2 and exoplayer-dash:r2.4.2
implementation ('com.facebook.android:audience-network-sdk:4.28.1') {
    exclude group: 'com.google.android.exoplayer', module:'exoplayer-core'
    exclude group: 'com.google.android.exoplayer', module:'exoplayer-dash'
}
Scenario 2: Abhängigkeiten in einer anderen Konfiguration
// Depends on version 1.3 of org.hamcrest:hamcrest-core 
implementation 'junit:junit:4.12' 
// Depends on version 1.1 of org.hamcrest:hamcrest-core
androidTestImplementation ('org.mockito:mockito-core:1.10.19'){
    exclude group: 'org.hamcrest', module:'hamcrest-core'
}

3: Definieren der entsprechenden Bibliothek explizit in Gradle

Dies ist eine saubere Methode, um Abhängigkeitskonflikte aus unterschiedlichen Konfigurationen aufzulösen. In diesem Fall müssen wir explizit angeben, welche Version der Bibliothek für die einzelnen Konfigurationen in den endgültigen Build eingebunden werden soll.

Dieser Ansatz vereinfacht die Auflösung von Konflikten, allerdings müssen Entwickler*innen beim Aktualisieren der tatsächlichen Abhängigkeiten wie junit und mockito die in Konflikt stehende Bibliothek ebenfalls aktualisieren.

// Depends on version 1.3 of org.hamcrest:hamcrest-core 
implementation 'junit:junit:4.12' 
// Depends on version 1.1 of org.hamcrest:hamcrest-core
androidTestImplementation 'org.mockito:mockito-core:1.10.19' 
// Explictly mention that include version 1.3 of org.hamcrest:hamcrest-core
androidTestCompile 'org.hamcrest:hamcrest-core:1.3' 

4: Erzwingen der Auflösung der Bibliothek

Bei dieser Art der Konfliktauflösung wird eine Bibliothek für alle Konfigurationen erzwungen, anstatt sie für eine Konfiguration zu deklarieren. Im folgenden Beispiel kannst du deine eigene „resolutionStrategy“ in build.gradle auf Modulebene hinzufügen, um unabhängig von Abhängigkeiten in derselben oder in anderen Konfigurationen zu erzwingen, dass die angegebene Version des Pakets eingebunden wird.

Dieser Ansatz sollte nur mit Vorsicht verwendet werden. Wenn in unserem ersten Beispiel „audience-network-sdk“ aktualisiert wird und diese Bibliotheken die Versionen der Bibliotheken „exoplayer-core“ und „exoplayer-dash“ aktualisieren, wird weiterhin eine veraltete Version verwendet. Dieses Szenario funktioniert zwar für den zweiten Lösungsansatz, allerdings erzwingen wir dabei die Version der Abhängigkeit für alle Konfigurationen anstatt für eine einzelne Konfiguration.

Szenario 1: Abhängigkeiten in der gleichen Konfiguration
android {
    configurations.all {
        resolutionStrategy.force 'com.google.android.exoplayer:exoplayer-core:r2.4.0'
        resolutionStrategy.force 'com.google.android.exoplayer:exoplayer-dash:r2.4.0'
    }
}
Scenario 2: Abhängigkeiten in einer anderen Konfiguration
android {
    configurations.all {
        resolutionStrategy.force 'org.hamcrest:hamcrest-core:1.1'
    }
}

Nächste Schritte

Weitere Ressourcen

Leitfaden für erste Schritte

Technischer Leitfaden für die ersten Schritte mit Audience Network

API-Referenz

Referenz zum Facebook-SDK für iOS