Android MAUI应用中Directory.GetFiles无法读取USB复制的外部存储文件
解决VS MAUI Android应用无法读取外置存储卡Download文件夹全部文件的问题
核心原因
问题源于Android 10及以上版本的**Scoped Storage(分区存储)**机制限制,以及MANAGE_EXTERNAL_STORAGE这类特殊权限需手动授权(仅在Manifest声明无效);同时硬编码外置存储路径也会导致兼容性问题。
具体解决步骤
1. 精简AndroidManifest权限
清理重复、无效权限,保留必要项:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <!-- 保留业务必需的其他权限,如CAMERA、INTERNET等 -->
WRITE_EXTERNAL_STORAGE添加maxSdkVersion="28"是因为Android 10+不再依赖该权限访问公共目录,由分区存储或MANAGE_EXTERNAL_STORAGE替代。
2. 引导用户授予MANAGE_EXTERNAL_STORAGE权限
该权限为特殊权限,无法通过常规弹窗申请,需跳转至应用设置手动开启:
using Android.Content; using Android.OS; using AndroidX.Core.App; // 在文件读取逻辑前调用 public void RequestFullStorageAccess() { if (Build.VERSION.SdkInt >= BuildVersionCodes.R) { if (!Environment.IsExternalStorageManager) { Intent intent = new Intent(Settings.ActionManageAppAllFilesAccessPermission); intent.SetData(Android.Net.Uri.Parse($"package:{Android.App.Application.Context.PackageName}")); StartActivityForResult(intent, 1001); } } } // 处理权限申请结果 protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) { base.OnActivityResult(requestCode, resultCode, data); if (requestCode == 1001) { if (Build.VERSION.SdkInt >= BuildVersionCodes.R && Environment.IsExternalStorageManager) { // 权限已授予,重新执行文件读取逻辑 LoadDownloadFiles(); } } }
3. 用系统API获取Download目录,避免硬编码路径
硬编码路径会导致设备兼容性问题,改用系统API获取正确路径:
// Android平台获取外置公共Download目录 string downloadPath = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath; // 读取文件 var files = Directory.GetFiles(downloadPath);
4. 适配Scoped Storage(无需特殊权限,可选)
若不想申请MANAGE_EXTERNAL_STORAGE(需Google Play审核),可通过MediaStore查询Download目录文件:
using Android.Content; using Android.Database; using Android.Provider; public List<string> GetAllDownloadFiles() { List<string> filePaths = new(); string[] projection = { MediaStore.Files.FileColumns.Data }; string selection = $"{MediaStore.Files.FileColumns.MediaType} = {MediaStore.Files.FileColumns.MediaTypeFile}"; string sortOrder = $"{MediaStore.Files.FileColumns.DateAdded} DESC"; using ICursor cursor = ContentResolver.Query(MediaStore.Files.GetContentUri("external"), projection, selection, null, sortOrder); if (cursor != null) { int dataIndex = cursor.GetColumnIndex(MediaStore.Files.FileColumns.Data); while (cursor.MoveToNext()) { string path = cursor.GetString(dataIndex); if (path.Contains(Android.OS.Environment.DirectoryDownloads)) filePaths.Add(path); } cursor.Close(); } return filePaths; }
这种方式符合分区存储规范,无需特殊权限,易通过应用商店审核。
验证流程
- 重新编译安装应用,首次运行引导用户开启「所有文件访问权限」(Android 11+)。
- 使用系统API路径读取文件,替换硬编码路径。
- 测试USB复制的文件是否能被正常列出。
内容的提问来源于stack exchange,提问作者Mats Claesgård
相关产品推荐
相关产品推荐

