PC パソコン

Android Studio「A failure occurred while executing MergeNativeLibsTask$MergeNativeLibsTaskWorkAction」の解決方法

Android Studioでビルドしたときに、「A failure occurred while executing MergeNativeLibsTask$MergeNativeLibsTaskWorkAction」というエラーが表示されることがあります。このエラーは、Android Gradle Pluginがアプリに含めるネイティブライブラリ(.soファイル)をまとめる処理で失敗したことを示します。エラーメッセージ自体は原因を直接示していないことが多いため、その直後に表示される詳細メッセージを確認することが重要です。

エラーの意味

Androidアプリでは、NDK、CMake、JNI、または広告SDK・ゲームSDK・画像処理SDKなどの依存ライブラリによって、lib/arm64-v8a/やlib/armeabi-v7a/などに.soファイルが含まれることがあります。ビルド時にはAndroid Gradle Pluginがこれらを集約しますが、同じパスの.soファイルが複数存在したり、パッケージング設定が競合したりすると、MergeNativeLibsTaskの処理が失敗します。

代表的な表示例

Execution failed for task ':app:mergeDebugNativeLibs'.
> A failure occurred while executing MergeNativeLibsTask$MergeNativeLibsTaskWorkAction

この下に、2 files found with path ...、重複した.soファイル名、対象ABIなど、より具体的な原因が表示されることがあります。

主な原因

1. 同じ.soファイルが複数の依存関係に含まれている

複数のAARやSDKが同じネイティブライブラリを内包していると、同一パスへ配置しようとして競合します。特にlibc++_shared.soの重複はよくある例です。

2. jniLibsとCMakeの両方から同じライブラリを追加している

src/main/jniLibsに手動配置した.soファイルが、CMakeや依存AARからも自動的にパッケージされる構成では、同じライブラリが二重に含まれることがあります。

3. 古いSDKや依存ライブラリが現在のAndroid Gradle Pluginと合っていない

古いAARやNDK関連ライブラリでは、現在のパッケージング方式と互換性がなく、ネイティブライブラリのマージ処理で問題が起きることがあります。

4. packaging設定が不適切

重複する.soファイルに対してpickFirstsやexcludesの指定が必要なのに設定されていない場合や、古いpackagingOptions設定が残っている場合に失敗することがあります。

5. ビルドキャッシュや中間生成物が壊れている

依存関係を変更した直後などに古い中間生成物が残り、実際の設定と一致しない状態でマージ処理が失敗する場合があります。

確認手順

1. エラーの直後にある詳細メッセージを確認する

まずBuild Outputを開き、MergeNativeLibsTaskWorkActionの行だけでなく、その数行下まで確認します。

./gradlew assembleDebug --stacktrace

Windowsでは次のように実行します。

gradlew.bat assembleDebug --stacktrace

必要に応じて--infoを追加すると、さらに詳しいログを確認できます。

./gradlew assembleDebug --info

2. 依存関係を確認する

どのライブラリがネイティブファイルを持ち込んでいるか確認するため、依存関係ツリーを表示します。

./gradlew app:dependencies

同じSDKが直接依存と推移的依存の両方から入っていないか、似た機能のSDKを複数導入していないか確認します。

3. jniLibsフォルダを確認する

次のようなフォルダに手動配置した.soファイルがある場合は、依存ライブラリ側にも同じファイルが含まれていないか確認します。

app/src/main/jniLibs/arm64-v8a/
app/src/main/jniLibs/armeabi-v7a/
app/src/main/jniLibs/x86/
app/src/main/jniLibs/x86_64/

解決方法

方法1. 重複している.soファイルの入力元を整理する

最も確実なのは、同じ.soファイルを複数経路から入れないようにすることです。CMakeやAARから自動的に含まれるライブラリをjniLibsにも手動配置している場合は、不要なコピーを削除します。

Android Gradle Pluginでは、外部ネイティブビルドで利用するプリビルドライブラリが自動的にパッケージされる場合があります。そのライブラリをさらにjniLibsとして指定すると重複の原因になります。

方法2. packagingのpickFirstsを設定する

複数の依存関係から同じ.soファイルが含まれ、どちらか一方を採用して問題ないことが明確な場合は、pickFirstsを使用できます。

Groovy DSLの例:

android {
    packaging {
        jniLibs {
            pickFirsts += ['**/libc++_shared.so']
        }
    }
}

Kotlin DSLの例:

android {
    packaging {
        jniLibs {
            pickFirsts += "**/libc++_shared.so"
        }
    }
}
pickFirstsは重複の根本原因を除去する設定ではありません。異なるバージョンの.soが競合している場合、どちらを採用しても安全とは限らないため、まず依存関係を整理してください。

方法3. 不要なネイティブライブラリを除外する

特定の.soファイルをアプリに含める必要がないことが分かっている場合は、excludesで除外できます。

android {
    packaging {
        jniLibs {
            excludes += ['**/不要なライブラリ名.so']
        }
    }
}

ただし、実行時に必要な.soを除外するとUnsatisfiedLinkErrorなどが発生するため、用途が分からないライブラリを安易に除外しないでください。

方法4. SDKや依存ライブラリを更新する

古いSDKを使っている場合は、最新版または現在のAndroid Gradle Pluginに対応したバージョンへ更新します。特に複数のSDKが同じC++ランタイムを含んでいる場合、SDK側の更新で重複が解消されることがあります。

方法5. 不要な依存関係を削除する

build.gradleまたはbuild.gradle.ktsを確認し、同じライブラリを異なるバージョンで複数指定していないか確認します。

dependencies {
    implementation 'com.example:library:最新版'
}

直接指定している依存関係と、別SDKから入ってくる推移的依存が競合している場合は、依存関係のバージョン統一や不要な依存の削除を検討します。

方法6. Clean後に再ビルドする

設定を修正した後は、中間生成物を削除して再ビルドします。

./gradlew clean
./gradlew assembleDebug

Android StudioではBuild → Clean Project、続けてBuild → Rebuild Projectを実行しても構いません。

注意点

  • MergeNativeLibsTaskWorkActionは上位の失敗メッセージなので、この1行だけで原因を決めつけないでください。
  • 重複エラーの場合は、どの依存関係から同じ.soが入っているかを特定することが重要です。
  • pickFirstsは便利ですが、異なるバイナリを無条件に1つへ絞ると実行時クラッシュにつながる可能性があります。
  • NDK、CMake、Android Gradle Plugin、外部SDKの組み合わせを変更した直後に発生した場合は、変更した依存関係から確認すると効率的です。
  • ネイティブライブラリを削除・除外した後は、必ず実機またはエミュレータで該当機能をテストしてください。

まとめ

「A failure occurred while executing MergeNativeLibsTask$MergeNativeLibsTaskWorkAction」は、Android Gradle Pluginが.soファイルを統合する段階で失敗したときに表示されるエラーです。まず詳細ログで本当の原因を確認し、重複した.soの入力元、jniLibs、CMake、依存AAR、packaging設定を順に確認します。重複経路を整理するのが最優先で、それでも必要な場合にpickFirstsやexcludesを使い、最後にCleanして再ビルドすると切り分けしやすくなります。