Android 12に最速で最低限対応してみた！

みなさんいかがお過ごしでしょうか？

私はこの前の週末、某大型商業施設で献血してきました。（400㎖）
プチ社会貢献できましたので、自己満足している今日この頃です。

ご褒美？に爽健美茶とアクエリアスのどっちか選んでね。と言われたので
お茶より「栄養」がありそうなアクエリアスにしました。あと箱ティッシュもらいました。
※飲み物配給は血抜き中に飲んでね、という意味でした。急に水分減るので。血抜き時間は5分ほどです。

ほて、そのときの出来事なんですけど、献血のバスの横をみるとタンカの上でおんなの人が倒れてました。
どうしたのかな？**早速血の供給を受けてるのかな？**と思ったんですが、ここは病院ではないのです。

どうやら血を抜きすぎて？**貧血を起こした**ようです。
かわいそう。

だいたい、体重50kgでも100kgオーバーでもおんなじ量抜くのが変なんですよね。

みなさん、くれぐれも献血しすぎには要注意です。

***

さて前置きが長くなりましたが、今回のお題は、Android 12対応です。
Pixel 6シリーズが発売されて、ぼちぼち使っている人が現れてますので、
こりゃ早く対応しないとマズいなと思いました。

しかし細かいところまで対応すると時間がかかるので、
最低限デバイスが動く＆アプリが落ちないようにしました。

では、はじめます。

## 環境
`Android Studio Arctic Fox | 2020.3.1 Patch 3`
`kotlin 1.5.31`

## まず、何したらいいんだろう。
一旦、予習、予習。
ひと通り読んでおいた方がいいですね。

Android 12 にアプリを移行する
https://developer.android.com/about/versions/12/migration

自分のアプリに関係しそうなところがちょいちょいありますね。

## よし、コード直していこ。

build.gradle を直します。（プロジェクトではなく、モジュールの方）

```gradle:build.gradle
compileSdkVersion 31
・
・
targetSdkVersion 31
```

## よっしゃ！ビルドするでえ！
はい、ビルドエラーになります。落ち着きましょう。

```
Manifest merger failed : android:exported needs to be explicitly specified for <activity>. 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. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details.
```

intent filterを設定しているactivityに「android:exported」の設定が必要です。
こんな感じです。

```xml:AndroidManifest.xml
<activity
    ※省略
    android:exported="true または false">
    <intent-filter>
        ※省略
    </intent-filter>
</activity>
```

ビルドします。

## ビルドはできたかな。動かそう。

うーん、アプリは起動しましたが、
どうやらデバイスの設定（Bluetooth接続や書込み）ができないですね。

ドキュメント読みます。（ちゃんと読まないと！）
<a href="https://developer.android.com/about/versions/12/features/bluetooth-permissions">Android 12 の新しい Bluetooth 権限</a>

はい、Bluetooth権限（実行時権限）まわりを直さないといけないです。

## ややこしやー。ややこしやー。
Android 12以降（APIレベル31）でBluetooth周りの権限が変わっとります。
こりゃ、コード書き分けないといかんようです。
（もっといい方法がないものか。。）

まず、マニフェストを修正します。

```xml:AndroidManifest.xml
    <uses-permission
        android:name="android.permission.BLUETOOTH"
        android:maxSdkVersion="30" />
    <uses-permission
        android:name="android.permission.BLUETOOTH_ADMIN"
        android:maxSdkVersion="30" />
    <uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission-sdk-23 android:name="android.permission.ACCESS_FINE_LOCATION" />
    <!-- ↓これを追加。 -->
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission
        android:name="android.permission.BLUETOOTH_SCAN"
        android:usesPermissionFlags="neverForLocation" />

```

- 「BLUETOOTH_SCAN」は、スキャンする必要がないときは必要ないです。（BDA直で接続する場合）
- 「android:usesPermissionFlags="neverForLocation"」はライブラリ依存になりますので、削除しないとダメな場合があります。
- 必要なところだけ追加してください。


そしてソースの方は、ものすっごいざっくり言いますと、こんな感じで実行時権限の処理を分けます。

```kotlin:関連するコトリン.kt
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
    // 12未満の処理
} else {
    // 12以降の処理（APIレベル31）
}
```

これがかなり手間でしたが、関連する箇所全部直して、またビルドします。

## よーし、動作確認するぞー。
あと、Push通知もみてみるか。

受信する操作してみます。

・
・
・

**いかん！アプリが落ちよるが！**

PendingIntent使っている箇所を直さないといけないようです。
※ライブラリがPendingIntentを使っているケースもあるので、要注意です。

これもちょうざっくりですが、こんな感じに直します。

```kotlin:関連するコトリン.kt
PendingIntent.getActivity(this, ｘｘｘ, ｘｘｘ, PendingIntent.FLAG_ONE_SHOT)
```

を

```kotlin:関連するコトリン.kt
PendingIntent.getActivity(this, ｘｘｘ, ｘｘｘ, PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE)
```

な感じに。

- PendingIntent.FLAG_IMMUTABLE にするか PendingIntent.FLAG_MUTABLE にするかはあなたのアプリ次第。FLAG_MUTABLEはAPIレベル25以上が必要です。

## その他：外部ブラウザ表示

外部ブラウザでPDF表示しようとしたら、
「ダウンロード」ディレクトリに保存されるようになりますねえ。

これは、、、アプリの動作として致命的ではないのでそのままでもいいんですが、
気になるときにはWebViewか、何かのPDFビューアで表示させた方がいいかもしれませんねえ。。

## その他：スプラッシュ表示

~~iOSではとっくの昔にできてるので、いまさら感満載だったのですが、~~
12でスプラッシュ表示できるようになってます！

<a href="https://developer.android.google.cn/about/versions/12/features/splash-screen?hl=ja-jp">スプラッシュ画面</a>

これは、スプラッシュアイコンをアニメーションできれいに作ることもできますが、
急ぎの場合は、アイコンと背景色が違っていたら色だけ合わせるといいかもしれません。

こんな感じです。（白くするとき）

```xml:styles.xml
<style name="Theme.AppCompat.Light.NoActionBar.FullScreen" parent="@style/Theme.AppCompat.Light">
    <!-- 以下を追加 -->
    <item name="android:windowSplashScreenBackground">@android:color/white</item><!-- スプラッシュ背景色 -->
    <item name="android:windowSplashScreenIconBackgroundColor">@android:color/white</item><!-- スプラッシュアイコン背景色 -->
</style>
```




今回は以上です。

また何か気づいたことがあれば、投稿します！