如何在Jetpack Compose中用Accompanist处理按钮点击时的运行时权限及永久拒绝判断
在Jetpack Compose中用Accompanist实现类似Dexter的权限处理(区分临时/永久拒绝)
问题场景
我正在用Accompanist库在Jetpack Compose中处理运行时权限,需求是点击按钮时完成以下逻辑:
- 权限授予:执行打开相册选择图片的操作
- 权限未授予:区分临时拒绝和永久拒绝,分别显示对应提示(永久拒绝时引导用户去设置页开启权限)
但现有代码无法判断权限是否被永久拒绝,希望实现类似Dexter库的权限处理行为。原代码如下:
原权限处理代码
val getImageLauncher = rememberLauncherForActivityResult( contract = GetContent() ) { uri -> uri?.let { viewModel.imagePicked.value = it.toString() } } // 读取存储权限状态 val readStoragePermissionState = rememberPermissionState( permission = READ_EXTERNAL_STORAGE ) { result -> if (result) { getImageLauncher.launch("image/*") } else { // 无法判断是否是永久拒绝 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() }
解决方案
Accompanist的rememberPermissionState提供了shouldShowRationale属性,可直接用来区分权限拒绝类型:
shouldShowRationale == true:用户临时拒绝权限,系统仍允许再次弹出权限请求弹窗shouldShowRationale == false:用户勾选了「不再询问」并拒绝,权限被永久拒绝
修改后的完整代码
权限状态与回调逻辑
val getImageLauncher = rememberLauncherForActivityResult( contract = GetContent() ) { uri -> uri?.let { viewModel.imagePicked.value = it.toString() } } // 读取存储权限状态 val readStoragePermissionState = rememberPermissionState( permission = READ_EXTERNAL_STORAGE ) { result -> if (result) { // 权限授予,打开相册 getImageLauncher.launch("image/*") } else { coroutineScope.launch { val snackbarText = if (!readStoragePermissionState.shouldShowRationale) { // 永久拒绝:提示用户去设置页开启权限 context.getString(R.string.read_storage_permanently_denied) } else { // 临时拒绝:仅提示需要权限 context.getString(R.string.read_storage_denied) } scaffoldState.snackbarHostState.showSnackbar(snackbarText) } } }
按钮触发逻辑(无需修改)
SecondaryOutlineButton( modifier = Modifier .fillMaxWidth() .height(48.dp), buttonText = stringResource(id = R.string.upload_image), buttonCornerRadius = 8.dp, ) { readStoragePermissionState.launchPermissionRequest() }
扩展:永久拒绝时直接跳转设置页
如果需要在永久拒绝时直接跳转到应用设置页,可在对应分支添加跳转逻辑:
// 跳转应用设置页示例 val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { data = Uri.fromParts("package", context.packageName, null) } context.startActivity(intent)
内容的提问来源于stack exchange,提问作者Malik Bilal
相关产品推荐
相关产品推荐

