Android 11+下Flutter文件管理器的PathAccessException问题求助
问题背景
我用Flutter开发安卓文件管理器,核心功能是遍历整个文件系统,筛选mp3、mp4、pdf文件供用户查看。但在Android 11及以上版本中触发PathAccessException,无法访问/storage/emulated/0/Android/data这类目录,需要在遍历文件时排除Android文件夹。
文件检索方法
Future<List<File>?> getFiles() async { Directory dir = Directory("/storage/emulated/0"); int totalSize = 0; List<File> files = []; if (dir.existsSync()) { List<FileSystemEntity> entities = dir.listSync(recursive: true); for (FileSystemEntity entity in entities) { if (entity is File) { File file = entity; String extension = file.path.split('.').last.toLowerCase(); if (extension == 'mp3' || extension == 'mp4' || extension == 'pdf') { int fileSizeInBytes = await file.length(); totalSize += fileSizeInBytes; files.add(file); } } } print("Total size : $totalSize bytes"); return files; } else { print("directory does not exist."); return null; } }
调用方式
List<File>? data = await provider.getFiles(); print(data);
异常信息
E/flutter ( 4188): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PathAccessException: Directory listing failed, path = '/storage/emulated/0/Android/data' (OS Error: Permission denied, errno = 13) E/flutter ( 4188): #0 _Directory._fillWithDirectoryListing (dart:io-patch/directory_patch.dart:42:24) E/flutter ( 4188): #1 _Directory.listSync (dart:io/directory_impl.dart:233:5) E/flutter ( 4188): #2 FileManagerProvider.getFiles (package:filesharing/src/screens/file_manager/provider/file_manager_provider.dart:73:45) E/flutter ( 4188): #3 _BottomTabsScreenState._getFiles (package:filesharing/src/screens/bottom_tabs/screens/bottom_tabs_screen.dart:49:39) E/flutter ( 4188): #4 _BottomTabsScreenState._init (package:filesharing/src/screens/bottom_tabs/screens/bottom_tabs_screen.dart:30:5) E/flutter ( 4188): <asynchronous suspension>
权限配置
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" /> <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
同时已在AndroidManifest.xml的<application>标签中添加:
android:requestLegacyExternalStorage="true"
解决方案
不要直接使用listSync(recursive: true),改为手动递归遍历目录,遇到Android文件夹直接跳过。修改后的getFiles方法如下:
Future<List<File>?> getFiles() async { Directory rootDir = Directory("/storage/emulated/0"); int totalSize = 0; List<File> files = []; if (!rootDir.existsSync()) { print("directory does not exist."); return null; } // 手动递归遍历目录 void traverseDirectory(Directory dir) { try { List<FileSystemEntity> entities = dir.listSync(); for (FileSystemEntity entity in entities) { // 排除Android文件夹 if (entity is Directory && entity.path.endsWith('/Android')) { continue; } if (entity is File) { String extension = entity.path.split('.').last.toLowerCase(); if (['mp3', 'mp4', 'pdf'].contains(extension)) { int fileSizeInBytes = entity.lengthSync(); totalSize += fileSizeInBytes; files.add(entity); } } else if (entity is Directory) { traverseDirectory(entity); } } } catch (e) { // 捕获权限异常,跳过无法访问的目录 print("无法访问目录: ${entity.path}, 错误: $e"); } } traverseDirectory(rootDir); print("Total size : $totalSize bytes"); return files; }
关键修改说明
- 移除
recursive: true参数,改为手动递归遍历,避免强制访问受限目录 - 检测到路径以
/Android结尾的目录时直接跳过 - 添加异常捕获,确保单个目录访问失败不会中断整个遍历流程
- 将
file.length()改为file.lengthSync(),避免异步嵌套导致的逻辑混乱
注意:即使拥有MANAGE_EXTERNAL_STORAGE权限,Android 11+系统也会限制对/Android/data、/Android/obb等目录的访问,因此必须主动排除这些目录才能避免权限异常。
内容的提问来源于stack exchange,提问作者MUHAMMAD WAQAS
相关产品推荐
相关产品推荐

