[Android] 016. 権限のリクエストと確認(Permission)

前回のAccompanistの紹介にも書いてありますがJetpack Compose向けの権限(Permission)まわりの実装がdeveloperサイトになさそうな感じだったので対応してみました

Permission周りの内容は以下で確認できます
https://developer.android.com/training/permissions/requesting?hl=ja
https://developer.android.com/codelabs/android-app-permissions?hl=ja#0

とりあえず画面が表示されたら通知の権限を確認して権限が許可されてなかったら許可を選択させる実装

ContextCompat.checkSelfPermissionで現在の権限の状態を確認
ActivityResultContracts.RequestPermissionで権限の選択のポップアップを表示でJetpack ComposeではrememberLauncherForActivityResultを使用します
ActivityCompat.shouldShowRequestPermissionRationaleで「今後表示しない」の状態の確認です
「今後表示しない」の仕様はAPI 30から変更されていてポップアップに表示されなく2回表示されたら今後表示されなくなります
今後表示されない状態の場合は権限の選択のポップアップは二度と表示されずユーザがAndroidの設定から手動で変更する必要があります
テストで再度確認したい場合はアプリを一旦アンインストールしてください

Manifest.permission.xxxを使用するために手動でimport android.Manifestを追加してください

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

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppScreen() {
    val context = LocalContext.current
    val activity = LocalContext.current as ComponentActivity
    var showAlert by remember { mutableStateOf(false) }
    val launcher = rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
        if (isGranted) {
            Log.d("App", "isGranted = true")
        } else {
            Log.d("App", "isGranted = false")

            if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.POST_NOTIFICATIONS)) {
                Log.d("App", "rationale = true")
            } else {
                Log.d("App", "rationale = false")
                showAlert = true
            }
        }
    }

    LaunchedEffect(Unit) {
        when(ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS)) {
            PackageManager.PERMISSION_GRANTED -> {
                Log.d("App", "PackageManager.PERMISSION_GRANTED")
            }
            PackageManager.PERMISSION_DENIED -> {
                Log.d("App", "PackageManager.PERMISSION_DENIED")
                launcher.launch(Manifest.permission.POST_NOTIFICATIONS)
            }
        }
    }

    if (showAlert) {
        AlertDialog(onDismissRequest = {}) {
            Column(modifier = Modifier.padding(16.dp)) {
                Text(text = "Androidの設定で権限を確認してください")
                Spacer(modifier = Modifier.height(24.dp))
                TextButton(
                    onClick = { showAlert = false },
                    modifier = Modifier.align(Alignment.End)
                ) {
                    Text("ok")
                }
            }
        }
    }
}

複数の権限の確認の場合はActivityResultContracts.RequestMultiplePermissionsを使用します
とりあえず通知と写真フォルダの場合は以下のような実装です
ここでは実装してないですがAlertDialogの表示内容は許可されていない権限が何かわかるようにした方が良いです

<manifest>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
import android.Manifest

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppScreen() {
    val permissions = listOf(Manifest.permission.POST_NOTIFICATIONS, Manifest.permission.READ_MEDIA_IMAGES)

    val context = LocalContext.current
    val activity = LocalContext.current as ComponentActivity
    var showAlert by remember { mutableStateOf(false) }
    val launcher = rememberLauncherForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result ->
        permissions.forEach {
            val isGranted = result[it] ?: false
            if (isGranted) {
                Log.d("App", "$it isGranted = true")
            } else {
                Log.d("App", "$it isGranted = false")
                if (ActivityCompat.shouldShowRequestPermissionRationale(activity, it)) {
                    Log.d("App", "$it rationale = true")
                } else {
                    Log.d("App", "$it rationale = false")
                    showAlert = true
                }
            }
        }
    }

    LaunchedEffect(Unit) {
        var isLaunch = false

        permissions.forEach {
            when(ContextCompat.checkSelfPermission(context, it)) {
                PackageManager.PERMISSION_GRANTED -> {
                    Log.d("App", "$it PackageManager.PERMISSION_GRANTED")
                }
                PackageManager.PERMISSION_DENIED -> {
                    Log.d("App", "$it PackageManager.PERMISSION_DENIED")
                    isLaunch = true
                }
            }
        }

        if (isLaunch) {
            launcher.launch(permissions.toTypedArray())
        }
    }

    if (showAlert) {
        AlertDialog(onDismissRequest = {}) {
            Column(modifier = Modifier.padding(16.dp)) {
                Text(text = "Androidの設定で権限を確認してください")
                Spacer(modifier = Modifier.height(24.dp))
                TextButton(
                    onClick = { showAlert = false },
                    modifier = Modifier.align(Alignment.End)
                ) {
                    Text("ok")
                }
            }
        }
    }
}

Android Studio Giraffe 2022.3.1 built on June 29, 2023