Android12から、セキュリティ面の改善を目的として、インテントフィルタを使用するアクティビティやサービスなどのコンポーネントでandroid:exported
属性を明示的に宣言する必要があります。
しかし私の手元では、インテントフィルタを使用する全てのコンポーネントでandroid:exported
属性を宣言したにも関わらず**「exported属性を指定してくれ」とエラーになってコンパイルできない事象**がありました。
そこでこの記事ではどのようにしてその事象を解決したかを紹介します。
結論
自分で用意したManifestではexported属性をちゃんと宣言してても、依存ライブラリでのManifestで条件を満たしていない場合、最終的にmergeされたManifest内で条件を満たさないことになるため、コンパイルエラーになります。
条件を満たしていないAndroidManifestを持つライブラリやモジュールを探し、(外部ライブラリの場合は)exported属性を宣言されてるバージョンにアップデートすることで解決できるかと思います。
前提条件
- Android12 SDKのセットアップが完了している
- 自分で定義したAndroidManifestファイル内で、インテントフィルタを使用する全てのコンポーネントで
android:exported
属性を宣言している
エラー内容
まず、コンパイルできなかった時のエラー内容は以下です。
Manifest merger failed with multiple errors, see log
Error: Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined
「Android12以上をターゲットにするときは、インテントフィルターが定義されてるコンポーネントにはandroid:exported
を明示してな」と怒られています。
なぜエラーになるか
でも、どんなに辛抱強くAndroidManifest内を見ても、インテントフィルターを定義してるコンポーネントでは、やっぱり全部exportedを宣言してるな。。。なぜだ。。。
とここで、先ほどのエラーログをもう一度見ると、Manifest merger failed with multiple errors
とあります。
そういえばそうだ、AndroidManifestは一つではなく、ライブラリの中にも含まれているんだった。
ドキュメントにはこうあります。
APK ファイルに含めることのできる AndroidManifest.xml ファイルは 1 つだけに限られますが、Android Studio プロジェクト内には、メイン ソースセットや、ビルド バリアント、インポート ライブラリによって提供される複数のマニフェスト ファイルを含めることができます。そのため、アプリをビルドする際、Gradle ビルドは、すべてのマニフェスト ファイルを単一のマニフェスト ファイルにマージし、APK 内にパッケージ化します。
なので、最終的にマージされたAndroidManifestを見てみます。
Merged Manifestを見る
メインモジュール(app
など)のAndroidManifest.xml
を開くと、実は下にMerged Manifest
というタブがあり、そこからプロジェクト内の、依存ライブラリも含んだ全てのAndroidManifest.xmlをマージしたManifestを見ることができます。
この統合されたManifestファイルを改めて眺めていくと。。。
おっ、この3つのactivityコンポーネントで、インテントフィルターが定義されてるのにexportedの宣言がないことが分かります。
原因はここにあった!!
で、こいつらのname
を見てみると、androidx.test:coreのライブラリであることが分かります。
依存ライブラリをアップデートする
Android Code Searchを使ってandroidx.test:core
のライブラリのアーティファクトを遡っていくと、androidx.test:core:1.3.1-alpha01
から、Manifestの各コンポーネントでexported属性が宣言されてるのが分かります。
もし私のプロジェクトでandroidx.test:core
の依存関係をbuild.gradleに宣言していたら話は早かったのですが、残念なことに私のプロジェクトではこのライブラリは直接宣言しておらず、なんのライブラリが間接的にこのtest:coreに依存しているのかを探さなければなりません。
そこで、テスト関連の他のライブラリが何に依存しているのかをmavenやAndroidX Techを使って一個一個確認していったところ、
- androidx.test.ext:junit:1.1.1 が androidx.test:core:1.2.1に依存している
- androidx.test.espresso:espresso-intents:3.1.1 が androidx.test:core:1.1.0に依存している
- androidx.fragment:fragment-testing:1.3.3 が androidx.test:core:1.3.0に依存している
ということが分かり、これらを、不要なものは削除しつつ、androidx.test:core:1.4.0
(1.3.1-alpha01以降)に依存しているバージョンまで上げることで解消することができました。
なお、私のプロジェクトでは、これ以外にも、
-
com.squareup.leakcanary:leakcanary-android:1.5.1
もManifestFileでexported属性が宣言されておらず、バージョンアップをしました。
結論
自分で用意したManifestではexported属性をちゃんと宣言してても、依存ライブラリでのManifestで条件を満たしていない場合、最終的にmergeされたManifest内で条件を満たさないことになるため、コンパイルエラーになります。
条件を満たしていないAndroidManifestを持つライブラリやモジュールを探し、(外部ライブラリの場合は)exported属性を宣言されてるバージョンにアップデートすることで解決できるかと思います。
あと、今回の場合、ライブラリを定期的に更新していれば、こんな色々調べる羽目にはならなかったと思うので、ライブラリは定期的に更新しましょう!!
参考