AndroidのSDK依存関係の解決

依存関係にまつわる問題は、ほかのいくつかのパッケージが依存している共有パッケージやライブラリがあるものの、依存しているそれらの共有パッケージのバージョンが異なっており互換性がないことに起因しています。Gradleによって、Android開発者の仕事は非常に容易になります - build.gradleで依存関係を1つ追加するだけで、必要なライブラリがシームレスにビルドに組み込まれます。しかし、2つの依存関係が同じライブラリの異なるバージョンに依存している場合はどうなりますか?

両方の依存関係が同じ構成(例: アプリ構成)に属しているなら、Gradleが自動的に依存関係を解決してくれます。例えば、Audience Network Android SDKは"exoplayer"ライブラリに依存しています。"exoplayer"ライブラリの別のバージョンを追加する必要がある場合、Gradleはより高いバージョンを選択してビルドに含めます。しかし、両方の依存関係が別々の構成に属している場合(例: アプリとテスト)、Gradleはエラーを出します。以下に、さまざまな競合と解決策を示します。

前提条件

続行する前に、必ずAudience NetworkのスタートガイドAndroidのスタートガイドすべてに目を通しておいてください。

依存関係の競合

1: 同じ構成の依存関係の共有ライブラリ

2: 異なる構成の依存関係の共有ライブラリ

依存関係の競合の解決策

1: Gradleに依存関係を解決させる

2: 依存関係の特定のバージョンを除外する

3: Gradleで競合ライブラリを明示的に定義する

4: ライブラリの解決を強制する



依存関係の競合

1: 同じ構成の依存関係の共有ライブラリ

次の例を考えてみましょう。下記のコードの依存関係は両方とも同じ構成に属しており、ライブラリ"org.hamcrest:hamcrest-core"に内的依存しています。両方の依存関係は同じライブラリの異なるバージョンを内的に使用しているため、高いほうのバージョンがビルドに含まれます。Gradle同期の出力は、最終ビルドのhamcrestライブラリのバージョンを1.1から 1.3に自動的にアップグレードすることを明確に示します。

// 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: 異なる構成の依存関係の共有ライブラリ

両方の依存関係が別々の構成に属している場合(例: アプリ構成とテスト構成)、Gradleはエラーを出します。次のコードスニペットを考えてみましょう。最初の依存関係はアプリ構成に属し、2番目の依存関係はテスト構成に属します。そのため、プロジェクトのビルド中にエラーが出て、ビルドは失敗します。

計装テストを実行すると、メインAPKとテストAPKの両方が同じクラスパスを共有します。メインAPKとテストAPKが同じライブラリ(例: Guava)の異なるバージョンを使用している場合、Gradleのビルドは失敗します。Gradleがこれを感知しなかった場合、アプリはテスト中と通常実行中で異なる動作をする場合があります(いずれかのケースでクラッシュするなど)。

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

依存関係の競合の解決策

1: Gradleに依存関係を解決させる

このアプローチは最もシンプルですが、同じ構成の依存関係に限定されます。 例えば、あなたのモジュールが明示的に特定のバージョンのExoPlayerに依存しているとします。しかし、Audience Network SDKにはすでに別のバージョンのExoPlayerが含まれています。デフォルトでは、高いほうのバージョンがビルドに含まれます。 以下のコードスニペットで、Gradle同期の出力は、最終ビルドのExoPlayerライブラリのバージョンがr2.4.2から2.7.3に自動的にアップグレードすることを明確に示します。

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: 依存関係の特定のバージョンを除外する

たいてい開発者は、どのバージョンのライブラリが最終的にビルドに含めるかを制御したいと思うものです。build.gradleを設定してそうすることができます。例えば、開発者がAudience Network SDKで、r2.4.2ではなくExoPlayer r2.4.0の低いバージョンを使用したいと思う場合、"audience-network-sdk"依存関係を宣言しながらそのモジュールを除外することができます。除外タグは異なる構成の依存関係にも適用されます。

実際のプロジェクトでは、同じライブラリの異なるバージョンを持つ依存関係はたくさんあります。その場合、依存関係ごとに、除外タグを使って、ライブラリの望むバージョンを含めることができます。

シナリオ1: 同じ構成の依存関係
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'
}
シナリオ2: 異なる構成の依存関係
// 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: Gradleで競合ライブラリを明示的に定義する

これは異なる構成の依存関係の競合をより簡潔に解決する方法です。この場合、いずれかの構成の最終ビルドに含めたいライブラリのバージョンを明示的に言及する必要があります。

このアプローチは競合を解決するためのより簡潔なアプローチですが、欠点として、開発者はjunitmockitoのような実際の依存関係をアップデートしながら、競合ライブラリもアップデートする必要があります。

// 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: ライブラリの解決を強制する

これは、競合を解決するもう一つの方法です。ここでは、1つの構成を宣言するのではなく、すべての構成に強制実行します。下記の例では、独自の"resolutionStrategy"をモジュールレベルのbuild.gradleに追加して、同じ構成か異なる構成に関係なく、パッケージの特定のバージョンが強制的に含まれるようにできます。

このアプローチは注意するべき点があります。最初の例では、audience-network-sdkがアップデートされ、これらのライブラリがexoplayer-coreとexopplayer-dashのライブラリバージョンをアップデートした場合、後方バージョンの使用を強制することになります。このシナリオでは2番目の解決アプローチも有効ですが、ここでは、1つの構成ではなくすべての構成で特定の依存関係バージョンを強制しています。

シナリオ1: 同じ構成の依存関係
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'
    }
}
シナリオ2: 異なる構成の依存関係
android {
    configurations.all {
        resolutionStrategy.force 'org.hamcrest:hamcrest-core:1.1'
    }
}

次のステップ

その他のリソース

スタートガイド

Audience Networkの利用を開始するためのテクニカルガイド

APIリファレンス

iOS用Facebook SDKのリファレンス