依存関係解決エラーをデバッグする

依存関係を追加すると、元の依存関係に必要な依存関係の問題や、依存関係のバージョン間で競合が発生することがあります。ここでは、依存関係グラフを分析し、発生する一般的な問題を修正する方法について説明します。

カスタム ビルド ロジックに関連する依存関係の解決エラーの修正方法については、カスタム依存関係の解決方針をご覧ください。

モジュールの依存関係を表示する

直接的な依存関係の中には、独自の依存関係を持つものもあります。これは、推移的な依存関係と呼ばれています。推移的な各依存関係を手動で宣言しなくても、Gradle ではこれらの依存関係が自動的に収集され、追加されます。Android Plugin for Gradle では、Gradle が特定のモジュールに対して解決する依存関係のリストを表示するタスクを提供しています。

また、各モジュールのレポートでは、ビルド バリアント、テスト ソースセット、クラスパスに基づいて依存関係がグループ化されます。以下に、アプリ モジュールのデバッグビルド バリアントのランタイム クラスパスと、インストゥルメント化されたテスト ソースセットのコンパイル クラスパスのサンプル レポートを示します。

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

このタスクを実行する手順は次のとおりです。

  1. [View] > [Tool Windows] > [Gradle] を選択します(または、ツール ウィンドウ バーの Gradle アイコン をクリックします)。
  2. AppName > [Tasks] > [android] の順に展開し、androidDependencies をダブルクリックします。Gradle がタスクを実行すると、[Run] ウィンドウが開いて出力が表示されます。

Gradle での依存関係の管理について詳しくは、Gradle ユーザーガイドの依存関係管理の基本をご覧ください。

推移的依存関係を除外する

アプリの規模が大きくなるにつれ、直接的な依存関係や推移的な依存関係(アプリがインポートしたライブラリが依存するライブラリ)など、多くの依存関係が含まれる可能性があります。不要になった推移的依存関係を除外するには、次のように exclude キーワードを使用します。

Kotlin

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

Groovy

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

推移的依存関係をテスト構成から除外する

テスト時に、特定の推移的な依存関係を除外する必要がある場合、上記のコードサンプルは期待どおりに動作しない可能性があります。これは、テスト構成(androidTestImplementation など)がモジュールの implementation 構成を拡張するためです。つまり、Gradle がこの構成を解決するときは、常に implementation 依存関係が含まれます。

したがって、テストから推移的依存関係を除外するには、実行時に除外する必要があります。次に例を示します。

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

注: 推移的依存関係を除外するセクションの元のコードサンプルに示されている依存関係ブロックで exclude キーワードを使用して、テスト構成に固有で他の構成には含まれない推移的依存関係を省略することもできます。

依存関係解決エラーを修正する

アプリのプロジェクトに複数の依存関係を追加すると、それらの直接的または推移的な依存関係の間に競合が発生する可能性があります。Android Gradle プラグインは競合を適切に解決しようと試みますが、一部の競合によりコンパイル時エラーまたは実行時エラーが発生することがあります。

どの依存関係がエラーの原因になっているかを調査するには、アプリの依存関係ツリーを検査し、複数回登場する依存関係または競合するバージョンを含む依存関係を探します。

重複する依存関係を簡単に見つけられない場合は、次のように Android Studio の UI を使用して、重複するクラスを含む依存関係を探します。

  1. メニューバーから [Navigate] > [Class] を選択します。
  2. ポップアップ検索ダイアログで、[Include non-project items] チェックボックスがオンになっていることを確認します。
  3. ビルドエラーで表示されるクラスの名前を入力します。
  4. このクラスを含む依存関係がないか結果を検査します。

次のセクションでは、依存関係の解決で発生する可能性のあるさまざまなタイプのエラーと、その修正方法について説明します。

重複クラスエラーを修正する

ランタイム クラスパスにクラスが複数回登場すると、次のようなエラーが発生します。

Program type already present com.example.MyClass

このエラーは通常、以下のいずれかの状況で発生します。

  • バイナリ依存関係に含まれているライブラリが、直接的な依存関係としてアプリにも含まれている場合。たとえば、アプリでライブラリ A とライブラリ B に対する直接的な依存関係が宣言されているものの、すでにライブラリ A のバイナリにライブラリ B が含まれている場合などです。
    • この問題を解決するには、ライブラリ B を直接的な依存関係から削除します。
  • アプリにローカル バイナリ依存関係があり、同じライブラリに対するリモート バイナリ依存関係がある。
    • この問題を解決するには、バイナリ依存関係の一方を削除します。

クラスパス間の競合を修正する

Gradle がコンパイル クラスパスを解決する際、まずランタイム クラスパスが解決され、その結果によりコンパイル クラスパスに追加する依存関係のバージョンが判定されます。つまり、ランタイム クラスパスにより、それ以降のクラスパスで同じ依存関係に必要なバージョン番号が決まります。

アプリのランタイム クラスパスによって、アプリのテスト APK のランタイム クラスパスで依存関係を照合するために Gradle が必要とするバージョン番号も決まります。クラスパスの階層を図 1 に示します。

図 1. 複数のクラスパスに登場する依存関係のバージョン番号のマッチングは、この階層に基づいて行われる必要があります。

たとえば、implementation 依存関係構成を使用するバージョンの依存関係がアプリに含まれ、runtimeOnly 構成を使用する別のバージョンの依存関係がライブラリ モジュールに含まれる場合、同じ依存関係の異なるバージョンが複数のクラスパスに登場する競合が発生する可能性があります。

3.3.0 以降の Android Gradle プラグインは、ランタイム クラスパスとコンパイル クラスパスへの依存関係を解決する際に、それ以降の特定のバージョン競合を自動的に修正しようと試みます。たとえば、ランタイム クラスパスにライブラリ A バージョン 2.0 が含まれ、コンパイル クラスパスにライブラリ A バージョン 1.0 が含まれている場合、プラグインはコンパイル クラスパスへの依存関係を自動的にライブラリ A バージョン 2.0 にアップデートして、エラーを回避します。

ただし、ランタイム クラスパスにライブラリ A バージョン 1.0 が含まれ、コンパイル クラスパスにライブラリ A バージョン 2.0 が含まれている場合、プラグインはコンパイル クラスパスへの依存関係をライブラリ A バージョン 1.0 にダウングレードしないため、以下のようなエラーが発生します。

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.

この問題を解決するには、以下のいずれかを行います。

  • 必要なバージョンの依存関係を api 依存関係としてライブラリ モジュールに含めます。これにより、ライブラリ モジュールでは依存関係を宣言するだけになりますが、アプリ モジュールはその API に推移的にアクセスします。
  • または、両方のモジュールに依存関係を宣言します。この場合、各モジュールが同じバージョンの依存関係を使用する必要があります。プロジェクト全体でプロパティの構成を行うことを考えて、プロジェクト全体で各依存関係のバージョンが一致するようにしてください。