Android 13文件选择器权限拒绝故障排查求助
Android 13 文件选择器权限拒绝问题解决方案
问题根源
Android 13(API 33+)对存储权限机制做了重大调整:
READ_EXTERNAL_STORAGE权限仅在API 32及以下生效(你已在Manifest中设置maxSdkVersion="32"),API 33+完全失效。- 媒体文件(图片、视频、音频)需通过
READ_MEDIA_IMAGES/READ_MEDIA_VIDEO/READ_MEDIA_AUDIO权限访问,且必须动态申请。 - 非媒体文件(PDF、TXT、RAR等)无需申请存储权限,但不能直接通过
File(path)访问文件路径——文件选择器返回的是SAF(存储访问框架)临时授权的URI,直接用File类访问会触发权限拒绝。
具体修复步骤
1. 调整文件选择后的处理逻辑
放弃直接通过路径创建File对象,改用file_picker提供的PlatformFile对象获取文件内容,避免直接路径访问。修改后的代码示例:
void pickAttachments() async { List<File> oldFiles = compressedFiles.isEmpty ? [] : compressedFiles; try { FilePickerResult? result = await FilePicker.platform.pickFiles( allowMultiple: true, allowCompression: true, type: FileType.custom, dialogTitle: "Pick files", allowedExtensions: [ 'jpg', 'jpeg', 'pdf', 'webp', 'mp4', 'mp3', 'rar', 'txt' ], withData: true, // 小文件可直接获取字节;大文件建议改用withReadStream ); if (result != null) { for (PlatformFile file in result.files) { File? localFile; // 优先尝试路径访问(部分场景仍支持) if (file.path != null) { localFile = File(file.path!); } // 路径不可用时,将字节写入临时文件 else if (file.bytes != null) { final tempDir = await getTemporaryDirectory(); localFile = File('${tempDir.path}/${file.name}'); await localFile.writeAsBytes(file.bytes!); } if (localFile != null) { String fileType = checkFileTypeUrl(localFile.path); if (fileType == "jpg") { File compressedFile = await attachmentCompressor( localFile, localFile.path.split('/').last, ); compressedFiles.add(compressedFile); debugPrint("File size ${getFileSizeString(bytes: compressedFile.lengthSync())}"); debugPrint("compressed and add"); } else { compressedFiles.add(localFile); } } } // 合并旧文件 compressedFiles.addAll(oldFiles); } else { debugPrint("No files selected !"); } } catch (e) { debugPrint("Error occurred ${e.toString()}"); } }
2. 确保媒体权限动态申请
对于图片、视频、音频类文件,需在代码中动态申请对应权限,示例逻辑:
import 'package:permission_handler/permission_handler.dart'; Future<bool> requestMediaPermissions() async { final statusImages = await Permission.photos.request(); final statusVideos = await Permission.videos.request(); final statusAudio = await Permission.audio.request(); return statusImages.isGranted && statusVideos.isGranted && statusAudio.isGranted; }
调用文件选择器前,先检查并申请权限:
void pickAttachments() async { bool hasMediaPerms = await requestMediaPermissions(); if (!hasMediaPerms) { debugPrint("媒体权限未授权"); return; } // 后续文件选择逻辑... }
3. 升级file_picker依赖
确保使用最新版本的file_picker包,旧版本对Android 13的SAF适配不完善。在pubspec.yaml中更新:
dependencies: file_picker: ^6.1.1 # 替换为最新稳定版
4. 避免使用MANAGE_EXTERNAL_STORAGE权限
虽然该权限可以实现全存储访问,但属于Google Play的受限权限,仅允许文件管理器类应用使用,普通应用申请会导致上架被拒,因此不建议采用。
内容的提问来源于stack exchange,提问作者Saurav
相关产品推荐
相关产品推荐

