Android 8.0+存储权限申请及onRequestPermissionsResult替代方案求助
解决存储权限适配与废弃权限回调替换问题
一、存储权限版本适配说明
- Android 8.0-9.0(API26-28):仍需申请
WRITE_EXTERNAL_STORAGE权限,逻辑与低版本一致。 - Android 10(API29):默认启用分区存储,若仅需读取相册图片,使用
ACTION_OPEN_DOCUMENT或MediaStore查询无需申请存储权限;若必须写入公共目录,需在Manifest中添加android:requestLegacyExternalStorage="true"(仅API29有效)。 - Android 11+(API30+):
- 读取媒体文件(图片/视频/音频):API33+用
READ_MEDIA_IMAGES/READ_MEDIA_VIDEO/READ_MEDIA_AUDIO,API30-32用READ_EXTERNAL_STORAGE。 - 写入公共目录或管理所有文件:需申请
MANAGE_EXTERNAL_STORAGE权限,且需引导用户跳转到系统设置页面授权(普通相册选图场景无需此权限)。
- 读取媒体文件(图片/视频/音频):API33+用
二、替换废弃的onRequestPermissionsResult()
使用registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions())处理权限请求,无需依赖请求码,逻辑更清晰。
完整代码示例
import android.Manifest import android.content.pm.PackageManager import android.os.Build import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat class ScannerActivity : AppCompatActivity() { // 相机+存储权限请求Launcher(按SDK版本适配权限) private val combinedPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions -> val cameraGranted = permissions[Manifest.permission.CAMERA] ?: false val storageGranted = getStoragePermissionGrantedStatus(permissions) when { cameraGranted && storageGranted -> pickImageCamera() cameraGranted -> { showToast("需要存储权限以访问相册") requestStoragePermission() } storageGranted -> { showToast("需要相机权限以扫描二维码") requestCameraPermission() } else -> showToast("相机和存储权限均为必需") } } // 单独存储权限请求Launcher private val storagePermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions -> if (getStoragePermissionGrantedStatus(permissions)) { pickImageGallery() } else { showToast("需要存储权限以访问相册") } } // 判断存储权限是否通过 private fun getStoragePermissionGrantedStatus(permissions: Map<String, Boolean>): Boolean { return when { Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> { permissions[Manifest.permission.READ_MEDIA_IMAGES] ?: false } Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> { permissions[Manifest.permission.READ_EXTERNAL_STORAGE] ?: false } else -> { permissions[Manifest.permission.WRITE_EXTERNAL_STORAGE] ?: false } } } // 检查相机权限 private fun checkCameraPermission(): Boolean { return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED } // 检查存储权限(按SDK版本适配) private fun checkStoragePermission(): Boolean { return when { Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> { ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES) == PackageManager.PERMISSION_GRANTED } Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> { ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED } else -> { ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED } } } // 请求相机+存储权限 private fun requestCameraAndStoragePermission() { val permissions = getCombinedPermissions() combinedPermissionLauncher.launch(permissions) } // 单独请求存储权限 private fun requestStoragePermission() { val permissions = getStoragePermissions() storagePermissionLauncher.launch(permissions) } // 单独请求相机权限 private fun requestCameraPermission() { combinedPermissionLauncher.launch(arrayOf(Manifest.permission.CAMERA)) } // 获取相机+存储权限数组(按SDK版本适配) private fun getCombinedPermissions(): Array<String> { return when { Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> { arrayOf(Manifest.permission.CAMERA, Manifest.permission.READ_MEDIA_IMAGES) } Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> { arrayOf(Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE) } else -> { arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE) } } } // 获取存储权限数组(按SDK版本适配) private fun getStoragePermissions(): Array<String> { return when { Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> { arrayOf(Manifest.permission.READ_MEDIA_IMAGES) } Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> { arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE) } else -> { arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE) } } } // 原有相机操作逻辑 private fun pickImageCamera() { // 你的相机启动代码 } // 原有相册操作逻辑 private fun pickImageGallery() { // 你的相册启动代码 } private fun showToast(message: String) { Toast.makeText(this, message, Toast.LENGTH_SHORT).show() } }
三、关键注意事项
- Manifest配置:
- API33+添加
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> - API30-32添加
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> - API29及以下添加
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> - API29需写入公共目录时,添加
<application android:requestLegacyExternalStorage="true">
- API33+添加
- 权限申请时机:在用户触发对应操作(如点击"从相册选图")时再申请权限,避免提前弹窗影响体验。
- 拒绝权限处理:若用户拒绝权限并勾选"不再询问",需引导用户到应用设置页手动开启,可通过
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(Uri.fromParts("package", packageName, null))跳转。
内容的提问来源于stack exchange,提问作者user23968783
相关产品推荐
相关产品推荐

