shouldShowRequestPermissionRationaleはAndroid APIのメソッドで、危険な権限をリクエストする前にユーザーに説明を表示する必要があるかどうかを開発者に伝えます。Android Developer Reference, 2024によると、このメソッドは、ユーザーが以前にリクエストを拒否したがNever Ask Againフラグを設定しなかった場合にtrueを返します。これは実行時の権限を扱う際に、丁寧なUXを構築するための重要なツールです。
重要なポイント
shouldShowRequestPermissionRationaleはAndroidのActivityおよびFragmentクラスのメソッドで、互換性のためにActivityCompatを介して利用できます。権限名を受け取り、再リクエスト前にユーザーに追加の説明を表示すべきかを示すBooleanを返します。このメソッドはAndroid 6.0 Marshmallowのランタイム権限モデルとともに登場しました。
理由説明メカニズムは、権限ダイアログとのユーザー操作履歴の追跡に基づいています。システムはユーザーが以前にリクエストを拒否したかどうかを記憶します。Never Ask Againフラグを設定せずに拒否が発生した場合、shouldShowRequestPermissionRationaleはtrueを返します。これは開発者へのシグナルです:ユーザーが権限の必要性を理解しておらず、追加の説明が必要です。Google Material Designガイドラインによると、最初の拒否後に理由説明ダイアログを表示すると、権限が再付与される確率が35パーセント向上します。
戻り値の意味を理解することが重要です:trueはダイアログを表示する意味があることを示し、falseはダイアログが不要(権限がすでに許可されているか一度もリクエストされていない)か無用(Never Ask Againが有効)であることを示します。このメソッドはダイアログが表示されることを保証するものではなく、推奨を与えるだけです。開発者が応答としてどのUIを表示するかを決定します。
shouldShowRequestPermissionRationaleはAPIレベル23で、ランタイム権限のためのメソッドグループとともに導入されました。Android 6.0以前は、すべての権限がインストール時にリクエストされ、説明メカニズムは不要でした。ユーザーはリスト全体を一度に受け入れるか拒否していました。ランタイムモデルにより、ユーザーがコンテキストを理解せずにリクエストを拒否することが可能になり、まさにそのために理由説明が必要なのです。
メソッドのロジックは次のように動作します。特定の権限に対するrequestPermissionsの最初の呼び出しでは、shouldShowRequestPermissionRationaleはfalseを返します — ユーザーはまだダイアログに遭遇していません。ユーザーがリクエストを拒否(Denyを押す)すると、メソッドはtrueを返し始めます。Never Ask Againフラグ付きで再度拒否された後、メソッドはfalseを返します。
完全な状態表:
| 状態 | shouldShowRationale | checkSelfPermission | 開発者の対応 |
|---|---|---|---|
| 未リクエスト | false | DENIED | システムダイアログを表示 |
| 許可済み | false | GRANTED | 機能を実行 |
| 初回拒否 | true | DENIED | 理由説明を表示、次にシステムダイアログ |
| Never Ask Again | false | DENIED | 設定にリダイレクト |
shouldShowRequestPermissionRationale = falseとcheckSelfPermission = DENIEDの組み合わせは、処理が最も難しいケースです。これは権限が一度もリクエストされていないか、Never Ask Againが設定されていることを意味します。開発者はこれら2つの状態を区別する必要があります。唯一の方法は、SharedPreferencesまたはSavedStateHandleを使用してisFirstRequestフラグを保存することです。最初のリクエストでフラグを設定し、フラグがすでにtrueである場合にshouldShowRationaleがfalseを返したら、それはNever Ask Againを意味します。
shouldShowRequestPermissionRationaleは、ユーザーがアプリをアンインストールして再インストールするか、アプリデータを消去するか、権限設定をリセットするとリセットされます。再インストール後、メソッドは最初のリクエストに対して再びfalseを返します。システムアップデートやAndroidバージョンの変更は履歴をリセットしません — 履歴はアプリデータに保存されます。
適切な理由説明の実装には3つのコンポーネントが含まれます:拒否後のshouldShowRequestPermissionRationaleの確認、説明付きのカスタムダイアログの表示、ユーザーの肯定的な応答後のrequestPermissionsの再呼び出しです。ダイアログは簡潔で具体的であり、アプリがこの特定の権限を必要とする理由を説明する必要があります。
private fun requestLocationWithRationale() {
val permission = Manifest.permission.ACCESS_FINE_LOCATION
when {
ContextCompat.checkSelfPermission(
this, permission
) == PackageManager.PERMISSION_GRANTED -> {
startLocationTracking()
}
ActivityCompat.shouldShowRequestPermissionRationale(
this, permission
) -> {
showRationaleDialog(permission)
}
else -> {
requestPermissionLauncher.launch(permission)
}
}
}
private fun showRationaleDialog(
permission: String
) {
AlertDialog.Builder(this)
.setTitle("位置情報へのアクセスが必要な理由")
.setMessage(
"アプリは地図上の場所をマークするために位置情報を使用します" +
"。この権限がないと" +
"機能は動作しません。"
)
.setPositiveButton("許可") { _, _ ->
requestPermissionLauncher.launch(permission)
}
.setNegativeButton("キャンセル", null)
.show()
}
Material Designのベストプラクティスでは、理由説明にはモーダルダイアログの代わりにボトムシートまたはインラインバナーを使用することを推奨しています。ボトムシートは邪魔にならず、ユーザーにコンテキストを提供します。画面上のインライン要素(説明と許可ボタンを備えたカードなど)は、権限なしでは機能が利用できないことを示しますが、他のインターフェースをブロックしません。
理由説明テキストはローカライズされ、特定の機能に適応させる必要があります。“アプリが動作するために必要です”のような一般的なフレーズは使用しないでください。具体的に指定してください:“あなたの近くの天気を表示するため”や“写真をギャラリーに保存するため”など。具体的な説明は、Google UXリサーチによると、権限付与の可能性を50パーセント向上させます。
の違いshouldShowRequestPermissionRationale = true(最初の拒否)とDENIEDを伴うfalse(Never Ask Again)は、権限処理における重要なポイントです。最初のケースでは、ユーザーはためらっており、追加の説明がアクセス許可を納得させる可能性があります。2番目のケースでは、ユーザーは最終決定を下しており、システムダイアログを繰り返してもイライラを引き起こすだけです。
拒否後の処理アルゴリズムは次のようになります:
順序を混同しないことが重要です:最初にshouldShowRequestPermissionRationaleを確認し、checkSelfPermissionではありません。checkSelfPermissionはどちらの場合もDENIEDを返します。shouldShowRequestPermissionRationaleだけが最初の拒否とNever Ask Againを区別します。“最初のリクエストが行われた”フラグを保存するにはSavedStateHandleまたはSharedPreferencesを使用してください — これが“未リクエスト”と“ブロック済み”を区別する唯一の信頼できる方法です。
理由説明を表示するのは一度だけにしてください。ユーザーが理由説明を見た後に再度リクエストを拒否した場合、説明を再度表示しないでください。すぐに設定を開くことを提案します。理由説明を繰り返し表示すると、迷惑と受け取られ、アプリの評価が下がります。最適なシナリオ:リクエスト — 拒否 — 理由説明 — 再リクエスト — 拒否 — 設定。
最初のリクエストの前に理由説明を表示しないでください。一部の開発者は、“ユーザーが理解する必要がある”と主張して、最初のダイアログの前に誤って説明を表示します。これはUXを損なります:ユーザーは1つではなく2つのダイアログを連続して見ることになります。Googleはシステムダイアログをすぐに表示し、理由説明は拒否後のみ表示することを推奨しています。
機能が実際に必要とされる瞬間に結びついたコンテキストに応じた理由説明を使用してください。アプリ起動時にすべての権限をリクエストしないでください — これが最も低い許可率です。ユーザーが「写真を撮る」ボタンを押したときにカメラをリクエストし、マップを開いたときに位置情報をリクエストします。コンテキストに応じたリクエストと理由説明を組み合わせると、起動時のリクエストの30パーセントに対して、許可率が80パーセントに向上します。
shouldShowRequestPermissionRationaleのテストでは、表の4つの状態(未リクエスト、許可済み、拒否、Never Ask Again)を確認する必要があります。単体テストでは、設定可能なshouldShowRationale動作を持つFakePermissionHandlerを使用します。インストルメンテーションテストでは、ダイアログ応答エミュレーション付きのUiAutomatorまたはEspressoを使用します。
class RationaleViewModelTest {
private val handler = FakePermissionHandler()
private val viewModel = PermissionsViewModel(handler)
fun testFirstDenial_shouldShowRationale() {
handler.shouldShowRationale = true
handler.cameraResult =
PermissionResult.DENIED(true)
viewModel.onCameraRequested()
assertEquals(
PermissionUiState.Denied(true),
viewModel.uiState.value
)
}
fun testNeverAskAgain_redirectToSettings() {
handler.shouldShowRationale = false
handler.cameraResult =
PermissionResult.DENIED(false)
viewModel.onCameraRequested()
assertEquals(
PermissionUiState.RedirectToSettings,
viewModel.uiState.value
)
}
}
インストルメンテーションテストの主要なシナリオは、最初の拒否後に理由説明ダイアログが実際に表示されることを確認することです。idling resources付きのEspressoを使用してシステムダイアログを待機し、Denyを押し、カスタム説明ダイアログの表示を確認し、Allowを押して許可を確認します。UIAutomatorはボタンテキストによってシステムダイアログと対話できるため、テストがより安定します。
また、理由説明ダイアログ内での拒否シナリオもテストする必要があります。ユーザーがカスタム説明でDenyを押した場合、Never Ask Againはまだ有効になっていないため、shouldShowRequestPermissionRationaleは再びtrueを返す必要があります。ベストプラクティスは、連続した2回の拒否後すぐに設定にリダイレクトして、繰り返しの説明でユーザーを煩わせず、アプリの評価を下げないようにすることです。
よくある質問
true — リクエストが以前に拒否され、Never Ask Againが設定されていない場合。false — 権限が一度もリクエストされていない、許可されている、または永久にブロックされている場合。false + DENIEDの組み合わせは追加のフラグによる確認が必要です。
shouldShowRequestPermissionRationaleがtrueを返した場合、ユーザーの最初の拒否後にのみ理由説明を表示します。最初のリクエスト前には理由説明は不要です — UXを悪化させ、不要なダイアログを生み出します。
SharedPreferencesまたはSavedStateHandleにisFirstRequestフラグを保存します。shouldShowRationale = false、checkSelfPermission = DENIED、フラグがtrueの場合 — Never Ask Againが有効です。フラグがfalseの場合 — 最初のリクエストです。
ユーザーをACTION_APPLICATION_DETAILS_SETTINGSにリダイレクトする「設定を開く」ボタン付きのダイアログを表示します。requestPermissionsを再度呼び出さないでください — ダイアログは表示されず、結果はメッセージなしでDENIEDとして返されます。
単体テストでは、設定可能なshouldShowRationaleフィールドを持つFakePermissionHandlerを使用します。インストルメンテーションテストでは、システムダイアログエミュレーション付きのEspressoまたはUIAutomatorを使用します。表の4つの状態すべてを確認します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。