UnityのAndroidアプリでAPIレベルを31(Android 12)に上げる際の対応

## はじめに

定期的にAndroidのOSバージョンが更新されるのに合わせて
Google Play Consoleにアプリをアップロードした際に「APIレベルを上げてください」という警告が出る場合があります。

今回、APIレベルを31(Android 12)に上げる必要がありましたが少し面倒なところがあったので対応した内容をまとめます。

## 環境

* Windows11
* Unity 2019.4.26f1

## SDKの更新対応

### 現状のUnityが参照しているSDKを調べる

Unityエディタを開いて
`Edit > Project Settings> Player > Other Settings > Identification`
の設定を確認します。
![ss01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2938978/a429eb8d-f08b-22ef-79b0-32da07ff1825.png)
TargetAPILevelが「Automatic(highest installed)」になっていればUnityが参照しているSDKの最新を設定していることになります。

次にUnityのインストールフォルダ内
`Editor\Data\PlaybackEngines\AndroidPlayer\SDK`
上記SDKフォルダ内にある「android-XX」を確認します。

ここのSDKの末尾の番号がAPIレベルに相当するので
更新したいAPIレベルのSDKが無い場合は追加する必要があります。

### Android Studio でSDKをダウンロードする

「Android Studio」を開いてSDK Managerを起動します。

追加したいAPIレベルのSDKにチェックを付けて右下の「Apply」を押してとダウンロードします。

ダウンロードしたSDKフォルダを先ほどのUnityが参照しているフォルダにコピーします。

以上でSDKの更新は完了です。
あとはapkファイルをビルドして実際にAPIレベル＝TargetSDKVersionが更新されているか確認します。

### AndroidROMのAPIレベル(TargetSDKVersion)を調べる

AndroidROMのAPIレベルはapkファイルのAndroidManifest.xmlに記載されている。
apkファイルはただの圧縮ファイルなので、中からAndroidManifest.xmlを取り出して内容を確認すればOKです。

参考：https://freelyapps.net/watch-android-manifest-in-apk/

---

基本的にはここまでの対応でAPIレベルの更新は完了です。

なのですがAPIレベル31(Android 12)にした際に追加で以下の対応が必要でした。

## android:exported 属性を明示的に宣言する

先ほどまでの時点でGoogle Play Consoleにアプリをアップロードとすると以下のようなことで怒られます。

公式ドキュメントより
https://developer.android.com/about/versions/12/behavior-changes-12?hl=ja

> Android 12 以降をターゲットとするアプリに、インテント フィルタを使用するアクティビティ、サービス、またはブロードキャスト レシーバが含まれている場合は、それらのアプリ コンポーネントで android:exported 属性を明示的に宣言する必要があります。

> 警告: インテント フィルタを使用するアクティビティ、サービス、またはブロードキャスト レシーバが android:exported の値を明示的に宣言していない場合、Android 12 以降を実行しているデバイスにアプリをインストールできません。


要は「インテントフィルタ」を使用しているアクティビティ、サービス、ブロードキャストレシーバに
android:exported 属性を明示的に宣言してくださいということです。

一か所でも漏れがあるとアプリのアップロード時に怒られます。

これらをどこで宣言するかですが
Androidアプリをビルドする際に使用しているAndroidManifestファイル内で宣言します。

AndroidManifestファイルを変更するために以下の設定をおこなっておきます。
`Edit > Project Settings> Player > Publishing Settings > Build`
こちらのCustumMainManifestにチェックをいれます。
![ss02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2938978/ad43bf14-c005-a05d-8507-7a1826fea064.png)

これでUnityプロジェクトで使用するAndroidManifestファイルの編集が可能になります。

### AndroidManifestにandroid:exported属性の宣言を追加

先ほどのAndroidManifestファイルを開き「intent-filter」が使用されている箇所を探します。

その「intent-filter」を含んでいる「activity」「service」「receiver」にandroid:exported属性の宣言を追加していきます。

```
例)
<activity android:name="com.unity3d.player.UnityPlayerActivity"
          android:label="@string/app_name"
          android:hardwareAccelerated="true"
          android:exported="true">　←　「activity」にandroid:exported属性を宣言
              <intent-filter>　←　「intent-filter」を含んでいる
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
              </intent-filter>
              <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
              <meta-data android:name="android.max_aspect" android:value="2.1" />
</activity>
```

android:exported属性の値ですが
https://developer.android.com/guide/topics/manifest/activity-element?hl=ja#exported

>android:exported
>この要素は、他のアプリのコンポーネントでアクティビティを起動できるかどうかを設定します。
「true」の場合、アクティビティはどのアプリからもアクセスでき、正確なクラス名で起動できます。
「false」の場合、アクティビティは、同じアプリのコンポーネント、同じユーザー ID を持つアプリ、または特権システム コンポーネントでしか起動できません。これは、インテント フィルタがない場合のデフォルト値です。

とのことなので用途にあわせて「true」か「false」を指定すればＯＫです。
※試しにメインのアクティビティで「false」を指定したらホーム画面からもアプリが起動しなくなりました。

### パッケージやプラグイン内のManifestにandroid:exported属性の宣言を追加

UnityプロジェクトでパッケージやプラグインにManifestファイルがある場合、
そちらのManifestファイルにもandroid:exported属性の宣言が必要になります。

基本的にはパッケージ側が対応してくれている(はず)ので
対象のパッケージのバージョンを上げることで勝手にandroid:exported属性の宣言がされますが

一部宣言がなかったり、そもそもバージョンを上げる事が難しい場合は
該当のパッケージ内にあるManifestファイルを直接編集する必要があります。

ちなみにビルドしたapkファイルのAndroidManifest.xmlに全てのManifestファイルの定義がありますので
対象のパッケージが分からない場合はapkファイルのAndroidManifestを開いて「intent-filter」の使用箇所を探すと良いです。

### Manifestファイルが見つからないない場合

これは私のUnityプロジェクトで起こったのですが
パッケージのアップデート、各Manifestファイルへのandroid:exported属性の追加を行っても
最終的にandroid:exported属性の宣言が抜けてしまうものがあり
どのManifestファイルで定義されているのか謎で詰まりました。

結論としては使用しているプラグインのaarファイル内にManifestファイルがあり
そこでの宣言が抜けていました。

aarファイル内のManifestファイルを編集する場合ですが、aarファイルはただ圧縮されているだけなので
aarファイルの拡張子をzipに変更すればエクスプローラー上で中身を展開して
テキストエディタ等で簡単に中身を編集する事ができます。
編集後、再度拡張子を「.aar」に戻せばOKです。


## 最後に

ビルドしてapkファイルを作成し、念のためAndroidManifestを確認。
Google Play Consoleにapkをアップロードしても怒られない事を確認。


## まとめ

APIレベルを31(Android 12)以上に上げる際には以下の対応が必要

・Unityが参照しているSDKの更新
・Manifestファイルへのandroid:exported属性の追加

プロジェクトで使用しているパッケージ、プラグインによってはすんなり終わるかと思います。