Men-debug error penyelesaian dependensi

Saat menambahkan dependensi, Anda mungkin mengalami masalah dengan dependensi yang diperlukan oleh dependensi asli, dan konflik di antara berbagai versi dependensi. Berikut ini cara menganalisis grafik dependensi dan memperbaiki masalah umum yang muncul.

Untuk panduan tentang cara memperbaiki error resolusi dependensi yang melibatkan build kustom logika, lihat Strategi resolusi dependensi kustom.

Menampilkan dependensi modul

Sebagian dependensi langsung mungkin memiliki dependensi sendiri. Dependensi semacam ini disebut dependensi transitif. Gradle mengumpulkan dan menambahkannya secara otomatis sehingga Anda tidak harus mendeklarasikan setiap dependensi transitif secara manual. Plugin Android untuk Gradle menyediakan tugas yang menampilkan daftar dependensi yang diselesaikan Gradle untuk modul tertentu.

Untuk setiap modul, laporan juga mengelompokkan dependensi berdasarkan varian build, set sumber pengujian, dan classpath. Berikut ini adalah laporan contoh untuk classpath runtime modul aplikasi dari varian build debug dan classpath kompilasi set sumber pengujian berinstrumen.

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

Untuk menjalankan tugas ini, lakukan langkah berikut:

  1. Pilih View > Tool Windows > Gradle (atau klik Gradle di kolom jendela alat).
  2. Perluas AppName > Tasks > android, lalu klik dua kali androidDependencies. Setelah Gradle mengeksekusi tugas, jendela Run akan terbuka untuk menampilkan output.

Untuk informasi selengkapnya tentang mengelola dependensi dalam Gradle, lihat Dasar-dasar pengelolaan dependensi di Panduan Pengguna Gradle.

Mengecualikan dependensi transitif

Seiring bertambahnya cakupan aplikasi, aplikasi dapat berisi sejumlah dependensi, termasuk dependensi langsung dan dependensi transitif (library yang digunakan oleh library yang diimpor milik aplikasi Anda). Untuk mengecualikan dependensi transitif yang sudah tidak dibutuhkan lagi, Anda dapat menggunakan kata kunci exclude seperti yang di bawah ini:

Kotlin

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

Groovy

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

Mengecualikan dependensi transitif dari konfigurasi pengujian

Jika Anda perlu mengecualikan dependensi transitif tertentu dari pengujian, contoh kode yang ditunjukkan di atas mungkin tidak berfungsi sesuai harapan. Hal ini dikarenakan konfigurasi pengujian (misalnya androidTestImplementation) akan memperluas konfigurasi implementation modul. Dengan kata lain, pengujian selalu berisi dependensi implementation saat Gradle mengatasi konfigurasi ini.

Jadi, untuk mengecualikan dependensi transitif dari pengujian, Anda harus melakukannya pada waktu eksekusi seperti ditunjukkan di bawah:

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'
}

Catatan: Anda tetap dapat menggunakan kata kunci exclude di blok dependensi seperti yang ditunjukkan dalam contoh kode asli dari bagian Mengecualikan dependensi transitif untuk menghilangkan dependensi transitif yang khusus untuk konfigurasi pengujian dan tidak termasuk dalam konfigurasi lain.

Memperbaiki error penyelesaian dependensi

Jika Anda menambahkan beberapa dependensi ke project aplikasi Anda, dependensi langsung dan transitif tersebut mungkin berkonflik satu sama lain. Plugin Android Gradle mencoba me-resolve konflik ini tanpa hambatan, tetapi beberapa konflik dapat menyebabkan error waktu kompilasi atau error runtime.

Untuk membantu Anda menyelidiki dependensi mana yang mengakibatkan error, periksa hierarki dependensi aplikasi Anda dan temukan dependensi yang muncul lebih dari sekali, atau yang muncul dengan versi yang mengalami konflik.

Jika Anda kesulitan mengenali dependensi duplikat, cobalah menggunakan UI Android Studio untuk menelusuri dependensi yang menyertakan class duplikat seperti berikut:

  1. Pilih Navigate > Class dari panel menu.
  2. Dalam dialog penelusuran pop-up, pastikan kotak di samping Include non-project items dicentang.
  3. Ketikkan nama class yang muncul dalam error build.
  4. Periksa hasilnya untuk menemukan dependensi yang menyertakan class tersebut.

Bagian berikut ini menjelaskan berbagai jenis error penyelesaian dependensi yang mungkin Anda jumpai dan cara memperbaikinya.

Memperbaiki error class duplikat

Jika sebuah class muncul lebih dari sekali pada classpath runtime, Anda akan mendapat error yang terlihat seperti berikut:

Program type already present com.example.MyClass

Error ini biasanya terjadi akibat salah satu keadaan berikut:

  • Sebuah dependensi biner menyertakan library yang juga disertakan oleh aplikasi Anda sebagai dependensi langsung. Misalnya, aplikasi Anda mendeklarasikan dependensi langsung pada Library A dan Library B, tetapi Library A sudah menyertakan Library B dalam binernya.
    • Untuk mengatasi masalah ini, hapus Library B sebagai dependensi langsung.
  • Aplikasi Anda memiliki dependensi biner lokal dan dependensi biner jarak jauh pada library yang sama.
    • Untuk mengatasi masalah ini, hapus salah satu dependensi biner.

Mengatasi konflik antar-classpath

Saat menangani classpath kompilasi, Gradle akan menangani classpath runtime terlebih dahulu dan menggunakan hasilnya untuk menentukan versi dependensi yang harus ditambahkan ke classpath kompilasi. Dengan kata lain, classpath runtime menentukan nomor versi yang diperlukan untuk dependensi identik pada classpath downstream.

Classpath runtime aplikasi Anda juga menentukan nomor versi yang diperlukan Gradle untuk mencocokkan dependensi dalam classpath runtime bagi APK pengujian aplikasi. Hierarki classpath dijelaskan dalam gambar 1.

Gambar 1. Nomor versi dependensi yang muncul di beberapa classpath harus cocok menurut hierarki ini.

Konflik ketika versi berbeda dari dependensi yang sama muncul di beberapa classpath dapat terjadi jika, misalnya, aplikasi Anda menyertakan versi dependensi menggunakan konfigurasi dependensi implementation sementara modul library menyertakan versi dependensi yang berbeda menggunakan konfigurasi runtimeOnly.

Saat menyelesaikan dependensi pada classpath runtime dan classpath waktu kompilasi, plugin Android Gradle 3.3.0 dan yang lebih tinggi mencoba untuk memperbaiki konflik versi downstream tertentu secara otomatis. Misalnya, jika classpath runtime menyertakan Library A versi 2.0 dan classpath kompilasi menyertakan Library A versi 1.0, plugin akan otomatis memperbarui dependensi pada classpath kompilasi ke Library A versi 2.0 untuk menghindari error.

Namun, jika classpath runtime menyertakan Library A versi 1.0 dan classpath kompilasi menyertakan Library A versi 2.0, plugin tidak akan mendowngrade dependensi pada classpath kompilasi ke Library A versi 1.0, dan Anda tetap mendapatkan error seperti berikut ini:

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.

Untuk mengatasi masalah ini, lakukan salah satu langkah berikut:

  • Sertakan versi dependensi yang diinginkan dari dependensi sebagai dependensi api ke modul library Anda. Artinya, hanya modul library Anda yang mendeklarasikan dependensi, tetapi secara transitif, modul aplikasi juga akan memiliki akses ke API-nya.
  • Atau, Anda dapat mendeklarasikan dependensi pada kedua modul, tetapi Anda harus memastikan bahwa setiap modul menggunakan versi dependensi yang sama. Sebaiknya konfigurasikan properti skala project untuk memastikan konsistensi versi setiap dependensi di seluruh project Anda.