D8: Program type already present: android.arch.core.internal.SafeIterableMap
Unityで作ったアプリに広告SDKをいれたらAndroidアプリビルド時に上記のようなエラーでビルド出来ない状態になってしまいました。
エラー内容や変更点から考えるとSDK追加時にライブラリの競合が発生していると思われます。
これまでネイティブのAndroidアプリでのライブラリ競合は経験していますが、Unityでは経験なかったので多少苦戦してしまいました。
今後のためにメモとして残しておきたいと思います。
環境:Unity version 2018.3.6f1 Personal
Unity でライブラリ同士の競合が発生した場合の対処法
まず、UnityではGooglePlayService関連のライブラリ競合問題を解決するための方法としては、
「Play Services Resolver」を使うのが一般的なようです。
「Play Services Resolver」はUnityのツールバーの「Assets」から使えます。
「Play Services Resolver」の「Force Resolve」を選択すると、ライブラリ同士の競合を解決してくれるらしいのですが、
複雑な構成になっている場合などは「Play Services Resolver」で解決できない場合もあるようです。
今回の場合、「Play Services Resolver」で解決できなかったので、別の手法を調べてみました。
Unity の「Play Services Resolver」で解決できない場合の対処法
上記の記事によると、「Play Services Resolver」で解決できない場合は、Gradleを使ってビルドする方法が有効らしいです。
Gradleを使ってビルドするためには、Unityが用意している「mainTemplate.gradle」のファイルを使います。
mainTemplate.gradleの場所は
「/Applications/Unity/PlaybackEngines/AndroidPlayer/Tools/GradleTemplates/mainTemplate.gradle」
あたりにありました。
環境によって多少違うかとは思いますが、僕のUnityの「mainTemplate.gradle」は下記のような感じでした。
// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN buildscript { repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.2.0' **BUILD_SCRIPT_DEPS**} } allprojects { repositories { google() jcenter() flatDir { dirs 'libs' } } } apply plugin: 'com.android.application' **APPLY_PLUGINS** dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) **DEPS**} android { compileSdkVersion **APIVERSION** buildToolsVersion '**BUILDTOOLS**' compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } defaultConfig { minSdkVersion **MINSDKVERSION** targetSdkVersion **TARGETSDKVERSION** applicationId '**APPLICATIONID**' ndk { abiFilters **ABIFILTERS** } versionCode **VERSIONCODE** versionName '**VERSIONNAME**' } lintOptions { abortOnError false } aaptOptions { noCompress = ['.unity3d', '.ress', '.resource', '.obb'**STREAMING_ASSETS**] }**SIGN** buildTypes { debug { minifyEnabled **MINIFY_DEBUG** useProguard **PROGUARD_DEBUG** proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-unity.txt'**USER_PROGUARD** jniDebuggable true } release { minifyEnabled **MINIFY_RELEASE** useProguard **PROGUARD_RELEASE** proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-unity.txt'**USER_PROGUARD****SIGNCONFIG** } }**PACKAGING_OPTIONS****SPLITS** **BUILT_APK_LOCATION** bundle { language { enableSplit = false } density { enableSplit = false } abi { enableSplit = true } } }**SPLITS_VERSION_CODE****REPOSITORIES****SOURCE_BUILD_SETUP**
このテンプレートをUnityプロジェクトの「Assets/Plugins/Android/」の下にコピーして、競合しているライブラリの競合を解決できる設定を行います。
ライブラリの競合調査
どのライブラリが競合しているかの調査ですが、調査方法としてはUnityからAndroidプロジェクトを出力して、
「gradlew dependencies」で調査する感じになるかと思います。
UnityからAndroidプロジェクトを出力する方法は、
「Unity」>「Build Settings」>「PlatformをAndroidに設定」>
「Export Projectにチェック」>「画面下のBuildがExportに変わる」>
「Exportを選択」でAndroidプロジェクトが出力できます。
Android プロジェクトのライブラリ競合の調査方法については以前書いたので省略します。
「gradlew dependencies」でライブラリの競合を調査して、Unityプロジェクトに配置した「mainTemplate.gradle」に除外するライブラリの指定等を書いていく感じになります。
ということでUnityで作ったAndroidアプリのライブラリ競合の調査・解決方法をまとめると、
- 「Play Services Resolver」で競合解決できるかチェック
- 「Play Services Resolver」で競合解決できない場合はAndroidプロジェクトを出力
- Androidプロジェクトで「gradlew dependencies」を使ってライブラリ競合調査
- 競合している部分を解決する設定を「Assets/Plugins/Android/mainTemplate.gradle」に書いて再度ビルド
- 全ての競合がなくなるまで繰り返す
という感じになるのかなと思います。
上記の手法で競合解決ができることはわかりましたが、これだとネイティブのAndroidに比べてライブラリの競合調査の手順が多少増えるので、
もっと効率的にできる方法がないか後で調べてみたいと思います。