Debugowanie błędów rozwiązywania zależności

Podczas dodawania zależności możesz napotkać problemy z zależnościami wymaganymi przez pierwotną zależność oraz konflikty między różnymi wersjami zależności. Oto, jak analizować graf zależności i rozwiązywać typowe problemy, które się pojawiają.

Wskazówki dotyczące rozwiązywania błędów związanych z rozwiązywaniem zależności, które obejmują niestandardową logikę kompilacji, znajdziesz w artykule Niestandardowe strategie rozwiązywania zależności.

Debugowanie błędów związanych z rozwiązywaniem zależności

To prompt prosi o pomoc dotyczącą debugowania konfliktów zależności.

Uruchom to okno w Android Studio, gdy masz otwarty plik build.gradle.

I'm getting the following error in my build: Conflict with dependency. Resolved versions for runtime classpath and compile classpath differ. What changes do I need to make to my dependencies to resolve this error.

Korzystanie z promptów AI

Prompty AI są przeznaczone do używania w Gemini w Android Studio (wymagana najnowsza wersja Canary).

Więcej informacji o Gemini w Studio znajdziesz tutaj: https://developer.android.com/studio/preview/gemini

Wyświetlanie zależności modułu

Niektóre zależności bezpośrednie mogą mieć własne zależności. Nazywamy je zależność pośrednią. Zamiast wymagać ręcznego deklarowania każdej biernej zależności Gradle automatycznie zbiera i dodaje je za Ciebie. Wtyczka Androida do obsługi Gradle udostępnia zadanie, które wyświetla listę zależności zdefiniowanych przez Gradle dla danego modułu.

W przypadku każdego modułu raport grupowanie zależności na podstawie wariantu kompilacji, testowanego zbioru źródeł i ścieżki klas. Poniżej znajduje się przykładowy raport z informacjami o klasie ścieżki pakietu runtime modułu aplikacji w wersji debugowej i z kompilowanej klasie ścieżki pakietu testowego zestawu źródeł z instrumentacją.

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
...

Aby uruchomić zadanie:

  1. Wybierz Widok > okna narzędzi > Gradle (lub kliknij Gradle na pasku okien narzędzi).
  2. Rozwiń AppName > Czynności > android i kliknij dwukrotnie androidDependencies. Gdy Gradle wykona zadanie, powinno otworzyć się okno Uruchom, w którym wyświetlą się dane wyjściowe.

Więcej informacji o zarządzaniu zależnościami w Gradle znajdziesz w podstawach zarządzania zależnościami w Przewodniku użytkownika Gradle.

Wykluczanie zależności pośrednich

Wraz z rozwojem aplikacji może ona zawierać wiele zależności, w tym zależności bezpośrednie i pośrednie (biblioteki, od których zależą zaimportowane biblioteki aplikacji). Aby wykluczyć zależności transitive, których już nie potrzebujesz, możesz użyć słowa kluczowego exclude w ten sposób:

Kotlin

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

Groovy

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

Wykluczanie zależności transitive z konfiguracji testów

Jeśli musisz wykluczyć z testów niektóre zależności pośrednie, kod pokazany powyżej może nie działać zgodnie z oczekiwaniami. Dzieje się tak, ponieważ konfiguracja testowa (np. androidTestImplementation) rozszerza konfigurację implementation modułu. Oznacza to, że zawsze zawiera zależności implementation, gdy Gradle rozwiązuje konfigurację.

Aby wykluczyć z testów zależności transitive, musisz to zrobić w czasie wykonywania, jak pokazano poniżej:

Kotlin

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

Groovy

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

Uwaga: nadal możesz używać słowa kluczowego exclude w bloku zależności, jak pokazano w pierwotnym przykładzie kodu w sekcji Wykluczanie zależności pośrednich, aby pominąć zależności pośrednie, które są specyficzne dla konfiguracji testowej i nie są uwzględniane w innych konfiguracjach.

Naprawianie błędów rozwiązywania zależności

Gdy dodasz do projektu aplikacji wiele zależności bezpośrednich i pośrednich, mogą one wchodzić ze sobą w kolizje. Wtyczka Gradle dla Androida próbuje rozwiązać te konflikty, ale niektóre z nich mogą spowodować błędy w czasie kompilacji lub w czasie wykonywania.

Aby ułatwić Ci ustalenie, które zależności powodują błędy, sprawdź drzewo zależności aplikacji i poszukaj zależności, które występują więcej niż raz lub mają sprzeczne wersje.

Jeśli nie możesz łatwo zidentyfikować zduplikowanej zależności, spróbuj użyć interfejsu użytkownika Android Studio, aby wyszukać zależności, które zawierają zduplikowaną klasę:

  1. Na pasku menu wybierz Przejdź > Klasa.
  2. W wyskakującym okienku wyszukiwania sprawdź, czy zaznaczone jest pole Uwzględnij elementy spoza projektu.
  3. Wpisz nazwę klasy, która pojawia się w błędzie kompilacji.
  4. Sprawdź wyniki pod kątem zależności, które obejmują zajęcia.

W sekcjach poniżej opisujemy różne typy błędów związanych z rozwiązywaniem zależności i sposoby ich naprawy.

Naprawianie błędów związanych z duplikowanymi klasami

Jeśli klasa pojawia się więcej niż raz w ścieżce klasyfikacji czasu wykonywania, pojawia się błąd podobny do tego:

Program type already present com.example.MyClass

Ten błąd występuje zwykle z jednego z tych powodów:

  • Zależność binarna obejmuje bibliotekę, która jest również zawarta w Twojej aplikacji jako zależność bezpośrednia. Na przykład aplikacja deklaruje bezpośrednią zależność od biblioteki A i biblioteki B, ale biblioteka A zawiera już bibliotekę B w swojej wersji binarnej.
    • Aby rozwiązać ten problem, usuń bibliotekę B jako bezpośrednią zależność.
  • Twoja aplikacja ma lokalną i zdalną zależność binarną z tej samej biblioteki.
    • Aby rozwiązać ten problem, usuń jedną z zależności binarnych.

Rozwiązywanie konfliktów między ścieżkami klas

Gdy Gradle rozwiązuje ścieżkę kompilacji, najpierw rozwiązuje ścieżkę czasu wykonania i na podstawie jej wyniku określa, które wersje zależności należy dodać do ścieżki kompilacji. Innymi słowy, classpath środowiska uruchomieniowego określa wymagane numery wersji identycznych zależności w dostępnych classpathach.

Ścieżka klas środowiskowej aplikacji określa też numery wersji, których Gradle wymaga do dopasowania zależności w ścieżce klas środowiskowej testowego pliku APK aplikacji. Hierarchię ścieżek klas opisano na rysunku 1.

Rysunek 1. Numery wersji zależności, które pojawiają się w różnych ścieżkach klas, muszą być zgodne zgodnie z tą hierarchią.

Konflikt, w którym różne wersje tej samej zależności występują w różnych ścieżkach klas, może wystąpić, gdy na przykład aplikacja zawiera wersję zależności z użyciem implementation konfiguracji zależności, a moduł biblioteki zawiera inną wersję tej zależności z użyciem konfiguracji runtimeOnly.

Podczas rozwiązywania zależności w czasie wykonywania i kompilowania ścieżki klasyfikacji plugin Gradle na Androida w wersji 3.3.0 lub nowszej automatycznie próbuje rozwiązać niektóre konflikty wersji. Jeśli na przykład classpath w czasie wykonywania zawiera bibliotekę A w wersji 2.0, a kompilacji – bibliotekę A w wersji 1.0, w celu uniknięcia błędów wtyczka automatycznie aktualizuje zależność w kompilacji do biblioteki A w wersji 2.0.

Jeśli jednak classpath środowiska wykonawczego zawiera bibliotekę A w wersji 1.0, a kompilacja classpath zawiera bibliotekę A w wersji 2.0, wtyczka nie obniża zależności w kompilacji classpath do biblioteki A w wersji 1.0 i nadal wyświetla błąd podobny do tego:

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.

Aby rozwiązać ten problem, wykonaj jedną z tych czynności:

  • Dodaj żądaną wersję zależności jako zależność api do modułu biblioteki. Oznacza to, że tylko moduł biblioteki deklaruje zależność, ale moduł aplikacji będzie miał również dostęp do jej interfejsu API w ramach zależności transitivejnej.
  • Możesz też zadeklarować zależność w obu modułach, ale musisz się wtedy upewnić, że każdy z nich używa tej samej wersji tej zależności. Rozważ skonfigurowanie właściwości w całym projekcie, aby zapewnić spójność wersji każdej zależności w całym projekcie.