Android SDK34下requestPermissions失效及权限弹窗不显示问题求助
问题修正方案(适配SDK34+)
核心问题说明
SDK34(Android 14)中requestPermissions()已被废弃,官方推荐使用Activity Result API处理权限请求;同时Android 13+对文件访问权限做了简化,使用系统文件选择器无需申请存储权限,这也是权限弹窗不弹出的原因之一。以下是完整修正代码:
步骤1:定义权限请求与操作启动器
在Fragment类中添加成员变量,替换废弃的权限请求方法:
import android.Manifest import android.app.Activity import android.content.ContentValues import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.net.Uri import android.provider.MediaStore import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import androidx.activity.result.contract.ActivityResultContracts class YourFragment : Fragment() { // 相机权限请求启动器 private val cameraPermissionLauncher = registerForActivityResult( ActivityResultContracts.RequestPermission() ) { isGranted -> if (isGranted) { presentCamera() } else { Toast.makeText(requireContext(), "需要相机权限才能拍照", Toast.LENGTH_SHORT).show() } } // 拍照结果处理启动器 private val takePictureLauncher = registerForActivityResult( ActivityResultContracts.TakePicture() ) { isSuccess -> if (isSuccess) { // 拍照成功,处理临时URI对应的图片 // 注意:此处需配合createImageUri()生成的URI使用 } } // 文件选择结果处理启动器(可选,替代startActivityForResult) private val filePickerLauncher = registerForActivityResult( ActivityResultContracts.StartActivityForResult() ) { result -> if (result.resultCode == Activity.RESULT_OK) { result.data?.data?.let { fileUri -> // 处理选中的文件URI } } }
步骤2:修正displayPicker函数
替换原权限检查逻辑,使用新启动器处理权限请求:
fun displayPicker() { val options = arrayOf("选择文件", "拍照") AlertDialog.Builder(requireContext()) .setTitle("选择操作") .setItems(options) { _, which -> when (which) { 0 -> { // SDK34下使用系统文件选择器无需申请存储权限 presentFiles() } 1 -> { // 检查相机权限 when { ContextCompat.checkSelfPermission( requireContext(), Manifest.permission.CAMERA ) == PackageManager.PERMISSION_GRANTED -> { presentCamera() } shouldShowRequestPermissionRationale(Manifest.permission.CAMERA) -> { // 显示权限说明弹窗 AlertDialog.Builder(requireContext()) .setMessage("需要相机权限拍摄照片,请允许") .setPositiveButton("确定") { _, _ -> cameraPermissionLauncher.launch(Manifest.permission.CAMERA) } .setNegativeButton("取消", null) .show() } else -> { // 直接发起权限请求 cameraPermissionLauncher.launch(Manifest.permission.CAMERA) } } } } } .show() }
步骤3:实现presentFiles与presentCamera
使用新API处理文件选择与拍照逻辑:
private fun presentFiles() { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { addCategory(Intent.CATEGORY_OPENABLE) type = "*/*" // 可指定具体类型,如"image/*"限制图片选择 } filePickerLauncher.launch(intent) } private fun presentCamera() { val photoUri = createImageUri() ?: run { Toast.makeText(requireContext(), "无法创建临时存储文件", Toast.LENGTH_SHORT).show() return } takePictureLauncher.launch(photoUri) } // 创建拍照临时文件URI private fun createImageUri(): Uri? { val contentValues = ContentValues().apply { put(MediaStore.Images.Media.DISPLAY_NAME, "photo_${System.currentTimeMillis()}.jpg") put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg") } return requireContext().contentResolver.insert( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues ) } }
关键注意点
- 存储权限无需申请:Android 13+使用
ACTION_OPEN_DOCUMENT调用系统文件选择器时,无需申请READ_EXTERNAL_STORAGE权限,系统会自动授予文件访问权限。 - 权限拒绝处理:若用户拒绝权限并勾选「不再询问」,
shouldShowRequestPermissionRationale会返回false,此时需引导用户前往应用设置手动开启权限。 - 废弃API替换:所有原
requestPermissions()、startActivityForResult()均需替换为Activity Result API,避免兼容性问题。
内容的提问来源于stack exchange,提问作者Kevin
相关产品推荐
相关产品推荐

