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

无需READ_MEDIA_IMAGES权限,Flutter如何列出FilePicker选中目录的文件?

无需READ_MEDIA_IMAGES权限列出FilePicker选中目录的媒体文件?

我当前的实现是用flutter_file_picker让用户选择目录,再列出其中媒体文件,代码如下:

String? selectedDirectory = await FilePicker.platform.getDirectoryPath();
if (selectedDirectory != null) {
  final files = Directory(selectedDirectory).list().toList();
  log(files.toString());
}

原本申请READ_MEDIA_IMAGES权限后功能正常,但根据Google Play 2024年中政策,需要移除该权限改用系统选择器,移除后仅能访问应用自身创建的文件,Android 13/14下无法读取目录中的其他媒体文件,请问有没有无需权限的实现方式?


解决方案:利用SAF(存储访问框架)实现无权限访问

Android 13+的存储权限机制限制了直接文件系统访问公共目录的媒体文件,但通过SAF获取的目录URI会带有系统临时授予的访问权限,可通过以下方式实现:

  1. 启用flutter_file_picker的SAF模式
    修改目录选择的调用代码,开启SAF模式,此时返回的是content://开头的URI(而非本地文件路径),带有临时访问权限:
String? selectedDirectory = await FilePicker.platform.getDirectoryPath(
  useSAF: true, // 关键:启用SAF模式
);
  1. 通过SAF API遍历目录下的媒体文件
    使用document_file_preview这类封装了SAF操作的插件,直接遍历选中目录下的文件并筛选媒体类型:
import 'package:document_file_preview/document_file_preview.dart';

if (selectedDirectory != null) {
  Uri directoryUri = Uri.parse(selectedDirectory);
  // 遍历目录下所有文件
  List<DocumentFile> allFiles = await DocumentFile.listFiles(uri: directoryUri);
  // 筛选图片/视频类媒体文件
  List<DocumentFile> mediaFiles = allFiles.where((file) {
    String? mimeType = file.mimeType;
    return mimeType?.startsWith('image/') == true || mimeType?.startsWith('video/') == true;
  }).toList();
  
  // 输出媒体文件信息
  for (var media in mediaFiles) {
    log('媒体文件:${media.name},路径:${media.uri}');
  }
}
  1. 或通过MediaStore查询指定目录的媒体文件
    如果你更倾向于用系统媒体库查询,可通过MediaStore结合SAF URI的路径匹配来获取目标目录下的媒体:
import 'package:media_store/media_store.dart';

if (selectedDirectory != null) {
  Uri directoryUri = Uri.parse(selectedDirectory);
  // 提取目录的相对路径用于匹配
  String targetPath = directoryUri.path.replaceFirst('/document/primary:', '');
  
  // 查询图片文件
  final imageCursor = await MediaStore.query(
    MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
    columns: [MediaStore.Images.Media.DATA, MediaStore.Images.Media.DISPLAY_NAME],
    where: "${MediaStore.Images.Media.RELATIVE_PATH} LIKE ?",
    whereArgs: ['$targetPath%'],
  );
  
  while (imageCursor.moveToNext()) {
    String fileName = imageCursor.getString(imageCursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME));
    String filePath = imageCursor.getString(imageCursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
    log('图片:$fileName,路径:$filePath');
  }
  imageCursor.close();
  
  // 同理可查询视频文件,替换为MediaStore.Videos.Media相关常量即可
}

关键说明

  • 不要使用Directory.list()直接访问:这属于直接文件系统操作,无权限时仅能访问应用私有目录,无法读取公共目录的媒体文件。
  • SAF的临时权限:通过useSAF: true获取的URI带有系统授予的临时访问权限,足够完成本次目录遍历操作,无需永久存储权限。
  • 符合Google Play政策:这种方式不需要申请READ_MEDIA_IMAGES/READ_MEDIA_VIDEO权限,完全符合政策中"改用系统选择器"的要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 03:12:29