You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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权限,且需引导用户跳转到系统设置页面授权(普通相册选图场景无需此权限)。

二、替换废弃的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">
  • 权限申请时机:在用户触发对应操作(如点击"从相册选图")时再申请权限,避免提前弹窗影响体验。
  • 拒绝权限处理:若用户拒绝权限并勾选"不再询问",需引导用户到应用设置页手动开启,可通过Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(Uri.fromParts("package", packageName, null))跳转。

内容的提问来源于stack exchange,提问作者user23968783

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 20:35:56