Android 13で導入されるNotification runtime permissionについて調べてみた

こんにちは。Androidエンジニアの宮本です。
マネーフォワード クラウド確定申告アプリの開発を担当しています。

マネーフォワードでは、毎月末に各部署のAndroidエンジニアが集まって開催している社内勉強会があります。
この社内勉強会では、毎回Android開発に関するテーマを1つ決めて深堀り、発表・ディスカッションを行っています。

本記事では2022年3月の社内勉強会で私が発表した、「Android 13で導入されるNotification runtime permission」について紹介します。

はじめに

2022年2月にAndroidの次期メジャーバージョン「Android 13」が発表されました。
本記事を執筆している2022年4月6日時点では、開発者向けプレビュー版の第2弾にあたる「Developer Preview 2」がリリースされています。

ドキュメントにはAndroid 13における変更点がまとめられています。
今回はこれらの変更点の内、通知機能を利用する際にユーザーへ要求する必要があるRuntime permissionについて解説します。

Runtime permissionとは、例えばカメラや位置情報、連絡先情報など、ユーザーの個人情報を含む可能性のある特別な機能・データにアクセスするために必要な権限のことです。
Android 13からは新たにアプリから通知を送信するために必要な権限が追加され、ユーザーからはこの権限の許可を得る必要があります。

本記事ではNotification runtime permissionのドキュメント通知機能の実装を体系的に学べるcodelabのアプリを題材に動作確認したことをまとめています。

今後のアップデートで内容に変更が入る可能性がありますのでご注意ください。

Android 13端末に新しくインストールされたアプリの通知機能への影響

完成形のcodelabのアプリを実行すると、SwitchをONにするとタイマーが起動し、カウントが0になると通知が送られてきます。

▼ Android 12端末でcodelabアプリを実行したときの挙動

ただし、Android 13からはユーザーからアプリから通知を送信するために必要な権限の許可を得ない限り、アプリから通知が送られません。
権限の許可をリクエストするには、targetSdkVersionが33かどうかで対応方法が異なります。

targetSdkVersionを33 (Preview版ではtargetSdkPreviewをTiramisu)にした場合

通知の送信の許可をリクエストする方法

権限リクエスト処理を何も対応せず、新しくアプリをインストールしてSwitchをONにしたところ、カウントが0になっても通知が送られませんでした。

通知の送信の許可を要求するには、AndroidManifest.xmlで以下のようにuses-permissionの追加をします。

<manifest ...>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    <application ...>
        ...
    </application>
</manifest>

そして、POST_NOTIFICATIONS 権限の許可をリクエストするための実装を追加します。
POST_NOTIFICATIONSはAPI Level33から利用できるため、targetSdkVersionを33にすることが必須です。

アプリの権限をリクエストするを参考にすると良いでしょう。
ここでは、SwitchをONにしたときに権限のリクエストを行います。

private val requestPermissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
            if (isGranted) {
                // 通知許可リクエストで許可を選択
                viewModel.startTimer()
            } else {
                // 通知許可リクエストで許可しないを選択
                binding.onOffSwitch.isChecked = false
                if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) {
                    Snackbar
                        .make(binding.root, "通知を受け取るには許可が必要です", Snackbar.LENGTH_LONG)
                        .show()
                } else {
                    // 権限を永続的に許可しない状態の場合は、
                    // 説明ダイアログを表示してアプリ情報の通知設定画面から権限変更を案内する
                    RequestPermissionAppSettingDialogFragment()
                        .show(childFragmentManager, RequestPermissionAppSettingDialogFragment.TAG)
                }
            }
        }

private fun checkNotificationPermission() {
    val notificationPermission = ContextCompat
                                     .checkSelfPermission(requireContext(), Manifest.permission.POST_NOTIFICATIONS)
    val notificationRationale = shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)

    if (notificationPermission == PackageManager.PERMISSION_GRANTED) {
        // 既に通知許可済み
        viewModel.startTimer()
    } else {
        if (notificationRationale) {
            // 以前に「許可をしない」を選択済みの場合は、説明ダイアログを表示して再度通知の許可をリクエストする
            PermissionRationaleDialogFragment().show(childFragmentManager, PermissionRationaleDialogFragment.TAG)
        } else {
            // 通知の許可をリクエストする
            requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
        }
    }
}

アプリを実行してSwitchをONにしてみると、下記のように通知の送信の許可をリクエストするシステムダイアログが表示されます。
「許可」を選択した場合、ダイアログが閉じて通知が送られるようになります。

通知許可のリクエストダイアログで「許可しない」を選択した場合

「許可しない」を選択した場合、そのアプリにおける全ての通知は送られません。
アプリのシステム設定では以下のような状態となり、全ての通知チャンネルがオフになります。

▼ アプリ情報の通知設定画面

再度SwitchをONにする際は、ユーザーになぜ権限の許可が必要なのか理由を添えて再度通知の送信の許可をリクエストするのが良いでしょう。

Android 11以降では「許可しない」を複数回タップした場合、Android 10以下では「今後表示しない」を選択した場合、通知の送信の許可をリクエストするシステムダイアログは表示されません。
許可するにはアプリ情報の通知設定画面で設定を変更する必要があるため、権限が必要な理由を添えて設定画面に遷移する導線を用意すると良いでしょう。

val intent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    // 直接通知の設定画面に遷移する
    Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { 
        putExtra(Settings.EXTRA_APP_PACKAGE, BuildConfig.APPLICATION_ID)
    }
} else {
    // アプリのシステム設定に遷移する
    Intent(
        Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
        Uri.fromParts("package", BuildConfig.APPLICATION_ID, null)
    )   
}
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)

targetSdkVersionが33の場合、通知許可のリクエストダイアログは2回目の「許可しない」を押すまで何回でも表示できます。

ダイアログの枠外をタップしてダイアログを閉じた場合

通知許可のリクエストダイアログで「許可」もしくは「許可しない」のいずれも選択せずにダイアログを閉じた場合は、通知は送られません。

再度通知許可のリクエストを行うことができます。

targetSdkVersionが32以下の場合

POST_NOTIFICATIONSはAPI Level33から利用できるため、targetSdkVersionが32以下のアプリでは開発者が任意のタイミングで通知許可のリクエストをすることができません。

Android 13のエミュレータでtargetSdkVersionが32以下の場合はどのような挙動になるか見てみましょう。

通知許可のリクエストが行われるタイミング

通知許可のリクエストダイアログは、通知チャンネルが作成されたタイミングでシステムが自動的に表示するとドキュメントに記載されています。
通知チャンネルは基本的に一度だけ作成すれば良いので、Applicationクラスでの初期化処理で行うことが多いでしょう。その場合はアプリの起動時にダイアログが表示されます。

▼ アプリ起動時に通知許可のリクエストダイアログが表示される挙動

ユーザー視点だとアプリを開いたら急に通知の送信の許可を求められる形になるため、なぜその許可が必要なのか具体的な理由がわからないまま選択することになります。
権限のリクエストの制御を柔軟に行うために、できるだけ早くtargetSdkVersionを33に上げて通知が必要な機能にユーザーがアクセスしたときに許可をリクエストするように対応するのが良いでしょう。

通知許可のリクエストダイアログで「許可しない」を選択した場合

「許可しない」を選択した場合、一度「許可しない」を選択した場合はアプリをアンインストールしてから再インストールするか、targetSdkVersionを33にしたアプリに更新するまで通知許可のリクエストダイアログは表示されません。

通知の送信を行えるようにするには、ユーザー自身でアプリ情報の通知設定画面を開いて設定を変更する必要があります。

ダイアログの枠外をタップしてダイアログを閉じた場合

通知許可のリクエストダイアログで「許可」もしくは「許可しない」のいずれも選択せずにダイアログを閉じた場合は、通知は送られません。
ダイアログはアプリを開く度に毎回表示されます。

通知の送信を行えるようにするには、ユーザー自身でアプリ情報の通知設定画面を開いて設定を変更するか、
再度アプリを開いたときに表示される通知許可のリクエストダイアログで「許可」を押す必要があります。

Android 12L以下からAndroid 13端末にアップグレードしたときの既存アプリの通知機能への影響

To minimize disruptions associated with the new notification permission, the system automatically grants the new notification permission temporarily to all eligible apps that are already installed on the user’s device prior to the system upgrade to Android 13.

ドキュメントに記載の通り、Android 13にアップグレードする前に自動で条件を満たした全てのインストール済みアプリに対して通知権限が一時的に許可されます。

一時的に権限が付与されるアプリの条件は、既に通知チャンネルが作成済みで、ユーザーによってアプリ情報の通知設定画面で通知を無効化していないことが必要です。
Android 12L以下の端末で通知を無効にしている場合は、端末をAndroid 13にアップグレードしても通知は無効のままとなります。

一時的に権限が許可されている期間

一時的に権限が許可される期間は、アプリのtargetSdkVersionによって異なります。

targetSdkVersionが33の場合

アプリが最初にアクティビティを起動するまで続きます。

そのため、Android 12L以下の端末で通知の設定を有効にしているアプリを使用している場合、Android 13にアップグレードして対象のアプリを起動するまでは通知を受け取れることになります。
アプリを起動すると一時的な権限許可期間は終了するため、前述した通知の送信の許可をユーザーにリクエストする必要があります。

targetSdkVersionが32以下の場合

ユーザーが通知許可のリクエストダイアログで「許可」もしくは「許可しない」を明示的に選択するまで続きます。

そのため、ダイアログの枠外をタップしてダイアログを閉じた場合は通知を受け取れることになります。

Android 12L以下の端末で動作するアプリの通知機能への影響

Developer Preview 2ではAndroid 12L以下の端末にアプリをインストールすることができないため、実際に手元で動作確認することはできませんでした。

ドキュメントによると、今回の変更はAndroid 13の端末で動作する全てのアプリが対象になるため、Android 12L以下の端末で動作するアプリの通知機能への影響は無いでしょう。

おわりに

Android 13で導入される Notification runtime permissionについて調べたことをまとめました。

Android 13上で動作し、通知機能を持つ全てのアプリについては従来と挙動が変わり、ユーザーから通知の送信の許可を得る必要があります。

ケース別の挙動をまとめると以下のようになります。

  • Android 13に新規でインストールしたアプリはユーザーから通知の送信の許可を得ない限り、アプリから通知が送られない
    • targetSdkVersion 33の場合は POST_NOTIFICATIONSのRuntime permissionの権限リクエストを行い、アプリから通知の送信を許可する必要がある
    • targetSdkVersion 32以下の場合は通知チャンネルが作成されたタイミングでシステムが自動的に権限のリクエストを行う
  • Android 12L以下の端末からAndroid 13にアップグレードした場合、既にインストールされているアプリは通知を無効化していない限り一時的に権限が許可される
    • targetSdkVersion 33の場合は、アプリが最初にアクティビティを起動するまで権限が一時的に許可される
    • targetSdkVersion 32以下の場合は、ユーザーが通知許可のリクエストダイアログで「許可」もしくは「許可しない」を明示的に選択するまで権限が一時的に許可される

もしこのようなアプリを開発されている場合はtargetSdkVersion 33への対応を早めに検討するのが良いでしょう。


マネーフォワードでは、エンジニアを募集しています。
ご応募お待ちしています。

【会社情報】
Wantedly
株式会社マネーフォワード
福岡開発拠点
関西開発拠点(大阪/京都)

【SNS】
マネーフォワード公式note
Twitter – 【公式】マネーフォワード
Twitter – Money Forward Developers
connpass – マネーフォワード
YouTube – Money Forward Developers

Pocket