android 如何处理jetpack作曲中伴奏者的运行时权限?

db2dz4w8  于 2023-01-24  发布在  Android
关注(0)|答案(3)|浏览(190)

我在jetpack compose中使用伴奏库来处理权限,文档中的示例代码没有处理权限的场景,比如检查按钮点击的权限。
所以我的场景是我想在点击按钮时检查运行时权限,如果权限被授予,则执行所需的工作,如果权限未被授予,则显示snackbar。但我不知道如何检查权限是否被永久拒绝。
我需要类似的行为,例如此库具有https://github.com/Karumi/Dexter

val getImageLauncher = rememberLauncherForActivityResult(
        contract = GetContent()
    ) { uri ->

        uri?.let {
            viewModel.imagePicked.value = it.toString()
        }
    }

    // Remember Read Storage Permission State
    val readStoragePermissionState = rememberPermissionState(
        permission = READ_EXTERNAL_STORAGE
    ) { result ->

        if (result) {
            getImageLauncher.launch("image/*")
        } else {

            // How can i check here if permission permanently denied?
            
            coroutineScope.launch {

                scaffoldState.snackbarHostState.showSnackbar(
                    context.getString(R.string.read_storage_denied)
                )
                
            }
        }
    }

下面是按钮的代码,当我单击它时,我想检查权限

SecondaryOutlineButton(
        modifier = Modifier
            .fillMaxWidth()
            .height(48.dp),
        buttonText = stringResource(
            id = R.string.upload_image
        ),
        buttonCornerRadius = 8.dp,
    ) {
        readStoragePermissionState.launchPermissionRequest()
    }
pftdvrlh

pftdvrlh1#

对于那些寻找类似场景的人。为了正确处理jetpack compose中的权限,我遵循了以下步骤:

1.当你点击这个按钮的时候,首先检查一下这个权限是否已经被授予了,如果已经被授予了,那么你只需做你需要做的事情。
1.如果未被授予,我们将检查shouldShouldRational是否为假。如果为假,我们将检查两种情况,因为shouldShowRationalism在两种情况下为假。第一种是永久拒绝权限。第二种是甚至未立即请求权限。对于管理,如果权限被永久拒绝或没有,我已经使用了共享的首选项。我已经为它编写了扩展函数,告诉我们权限是否被请求过一次。
1.对于上面的第一种情况,我将显示小吃店告诉用户您永久拒绝了允许该权限的权限打开设置;对于上面的第二种情况,我将启动显示系统权限对话框的请求,并通过扩展功能更新共享偏好。
1.对于shouldShowRationalism为真的情况,我将向用户显示一个小吃店,解释为什么需要权限,并与操作沿着再次请求系统权限对话框。
1.最后,无论何时授予权限,我都可以在rememberPermissionState回调中完成所需的工作。

val context = LocalContext.current

val scaffoldState = rememberScaffoldState()

val coroutineScope = rememberCoroutineScope()

val getImageLauncher = rememberLauncherForActivityResult(
    contract = GetContent()
) { uri ->

    uri?.let {
        viewModel.imagePicked.value = it.toString()
    }
}

// Remember Read Storage Permission State
val readStoragePermissionState = rememberPermissionState(
    permission = READ_EXTERNAL_STORAGE
) { granted ->

    if (granted) {
        getImageLauncher.launch("image/*")
    }
}

按钮可组合

SecondaryOutlineButton(
    modifier = Modifier
        .fillMaxWidth()
        .height(48.dp),
    buttonText = stringResource(
        id = R.string.upload_image
    ),
    buttonCornerRadius = 8.dp,
) {
    // This is onClick Callback of My Custom Composable Button
    with(readStoragePermissionState) {

        when {

            // If Permission is Already Granted to the Application
            status.isGranted -> {
                getImageLauncher.launch("image/*")
            }

            // If Permission is Asked First or Denied Permanently
            !status.shouldShowRationale -> {

                context.isPermissionAskedForFirstTime(
                    permission = permission
                ).also { result ->

                    if (result) {

                        launchPermissionRequest()

                        context.permissionAskedForFirsTime(
                            permission = permission
                        )

                    } else {

                        coroutineScope.launch {

                            with(scaffoldState.snackbarHostState) {

                                val snackbarResult =
                                    showSnackbar(
                                        message = context.getString(
                                            R.string.read_storage_denied
                                        ),
                                        actionLabel = context.getString(
                                            R.string.settings
                                        )
                                    )

                                when (snackbarResult) {
                                    // Open this Application General Settings.
                                    SnackbarResult.ActionPerformed -> {
                                        context.openApplicationSettings()
                                    }

                                    SnackbarResult.Dismissed -> Unit
                                }
                            }
                        }
                    }
                }
            }

            // If You should Tell User Why this Permission Required
            status.shouldShowRationale -> {

                coroutineScope.launch {

                    with(scaffoldState.snackbarHostState) {

                        val snackbarResult = showSnackbar(
                            message = context.getString(
                                R.string.read_storage_rational
                            ),
                            actionLabel = context.getString(
                                R.string.allow
                            )
                        )

                        when (snackbarResult) {
                            // Request for System Permission Dialog Again.
                            SnackbarResult.ActionPerformed -> {
                                launchPermissionRequest()
                            }

                            SnackbarResult.Dismissed -> Unit
                        }
                    }
                }
            }

            else -> Unit
        }
    }
}

扩展函数

fun Context.isPermissionAskedForFirstTime(
    permission: String
): Boolean {

    return getSharedPreferences(
        packageName, MODE_PRIVATE
    ).getBoolean(permission, true)
}

fun Context.permissionAskedForFirsTime(
    permission: String
) {
    getSharedPreferences(
        packageName, MODE_PRIVATE
    ).edit().putBoolean(permission, false).apply()
}

fun Context.openApplicationSettings() {
    startActivity(Intent().apply {
        action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
        data = Uri.parse("package:${packageName}")
    })
}

我使用的是implementation "com.google.accompanist:accompanist-permissions:0.25.0"

koaltpgm

koaltpgm2#

我使用了Philipp Lackner的tutorial,他创建了一个扩展方法,以防权限被永久拒绝。
所以在你的按钮代码中,你会有一个方法来完成这个任务:

Manifest.permission.CAMERA -> {
                    when {
                        perm.status.isGranted -> {                                                                 
                          PermissionText(text = "Camera permission accepted.")
                          }

                        perm.status.shouldShowRationale -> {
                            PermissionText(text = "Camera permission is needed to take pictures.")
                        }

                        perm.isPermanentlyDenied() -> {
                            PermissionText(text = "Camera permission was permanently denied. You can enable it in the app settings.")
                        }
                    }
                }

扩展名为:

@ExperimentalPermissionsApi
fun PermissionState.isPermanentlyDenied(): Boolean {
    return !status.shouldShowRationale && !status.isGranted
}
57hvy0tb

57hvy0tb3#

下面的代码完全符合您的要求:
单击按钮(FAB),如果已授予权限,则开始工作。如果未授予权限,则在请求之前检查是否需要向用户显示更多信息(shouldShowRationality),并在需要时显示SnackBar。否则,只需请求权限(如果已授予权限,则开始工作)。
请记住,现在无法检查权限是否被永久拒绝。shouldShowRationale()在不同版本的Android中的工作方式不同。您可以做的(参见代码)是,如果shouldShowRationale()返回true,则显示SnackBar。

@Composable
fun OptionalPermissionScreen() {
    val context = LocalContext.current.applicationContext

    val state = rememberPermissionState(Manifest.permission.CAMERA)
    val scaffoldState = rememberScaffoldState()
    val launcher = rememberLauncherForActivityResult(RequestPermission()) { wasGranted ->
        if (wasGranted) {
            // TODO do work (ie forward to viewmodel)
            Toast.makeText(context, "📸 Photo in 3..2..1", Toast.LENGTH_SHORT).show()
        }
    }
    Scaffold(
        modifier = Modifier.fillMaxSize(),
        scaffoldState = scaffoldState,
        floatingActionButton = {
            val scope = rememberCoroutineScope()
            val snackbarHostState = scaffoldState.snackbarHostState

            FloatingActionButton(onClick = {
                when (state.status) {
                    PermissionStatus.Granted -> {
                        // TODO do work (ie forward to viewmodel)
                        Toast.makeText(context, "📸 Photo in 3..2..1", Toast.LENGTH_SHORT).show()
                    }
                    else -> {
                        if (state.status.shouldShowRationale) {
                            scope.launch {
                                val result =
                                    snackbarHostState.showSnackbar(
                                        message = "Permission required",
                                        actionLabel = "Go to settings"
                                    )
                                if (result == SnackbarResult.ActionPerformed) {
                                    val intent = Intent(
                                        Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
                                        Uri.fromParts("package", context.packageName, null)
                                    )
                                    startActivity(intent)
                                }
                            }
                        } else {
                            launcher.launch(Manifest.permission.CAMERA)
                        }
                    }
                }
            }) {
                Icon(Icons.Rounded.Camera, contentDescription = null)
            }
        }) {
        // the rest of your screen
    }
}

by clicking here工作原理的视频。
这是blog post I wrote on permissions in Jetpack Compose的一部分。

相关问题