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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 11:10:53