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及以上已不再需要:写入应用私有目录无需权限,写入共享媒体库可通过MediaStoreAPI完成
修复步骤
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)可直接操作;写入共享媒体库通过MediaStoreAPI自动处理权限
内容的提问来源于stack exchange,提问作者ZakouCrokant
相关产品推荐
相关产品推荐

