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

Android Compose外部存储读写权限申请无弹窗且未授权问题求助

问题解决:Android 13(API33)下外部存储权限申请无弹窗且返回未授权

核心原因

你的项目targetSdk为33(对应Android 13),该版本对外部存储权限做了重大调整:

  • READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限已被废弃,系统不会为这两个权限弹出申请弹窗,直接返回未授权状态
  • 读取媒体文件(图片、视频、音频)需使用新的细分权限:READ_MEDIA_IMAGES、READ_MEDIA_VIDEO、READ_MEDIA_AUDIO
  • WRITE_EXTERNAL_STORAGE在API30及以上已不再需要:写入应用私有目录无需权限,写入共享媒体库可通过MediaStore API完成

修复步骤

1. 更新Manifest权限

在AndroidManifest.xml中添加适配API33的媒体权限,同时保留旧权限以兼容低版本:

<!-- 兼容API30以下版本 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />

<!-- API33+读取媒体所需权限,按需添加对应类型 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />

2. 修改权限申请代码

根据SDK版本动态判断要申请的权限,替换原有的旧权限:

单权限申请示例(以读取图片为例)

@Composable
fun PermissionButton(
    toast: () -> Unit
) {
    val readPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        // API33+ 读取图片权限,按需替换为READ_MEDIA_VIDEO或READ_MEDIA_AUDIO
        Manifest.permission.READ_MEDIA_IMAGES
    } else {
        Manifest.permission.READ_EXTERNAL_STORAGE
    }

    val permissionResultLauncher = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.RequestPermission(),
        onResult = { isGranted ->
            if (isGranted) {
                toast()
            } else {
                Log.e("MainActivity", "ERROR PERMISSION NOT GRANTED")
                Log.e("MainActivity", "Permission = $isGranted")
            }
        }
    )

    Button(onClick = {
        permissionResultLauncher.launch(readPermission)
    }) {
        Text("Permission asking button")
    }
}

多权限申请示例(同时读取图片+视频)

@Composable
fun PermissionButton(
    toast: () -> Unit
) {
    val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        arrayOf(
            Manifest.permission.READ_MEDIA_IMAGES,
            Manifest.permission.READ_MEDIA_VIDEO
        )
    } else {
        arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE)
    }

    val permissionResultLauncher = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.RequestMultiplePermissions(),
        onResult = { results ->
            val allGranted = results.all { it.value }
            if (allGranted) {
                toast()
            } else {
                Log.e("MainActivity", "ERROR PERMISSIONS NOT GRANTED")
                results.forEach { (permission, isGranted) ->
                    Log.e("MainActivity", "$permission = $isGranted")
                }
            }
        }
    )

    Button(onClick = {
        permissionResultLauncher.launch(permissions)
    }) {
        Text("Permission asking button")
    }
}

3. 补充说明

  • 若需读取非媒体文件(如文档),API33+需使用ACTION_OPEN_DOCUMENT或ACTION_GET_CONTENT文件选择器,无需申请权限
  • 写入操作无需WRITE_EXTERNAL_STORAGE:写入应用私有目录(context.filesDir或context.cacheDir)可直接操作;写入共享媒体库通过MediaStore API自动处理权限

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 23:03:34