为何X-plore可列出安卓全目录,而System.IO.Directory.GetDirectories却遭权限拒绝?
解决Xamarin Android访问/storage/emulated/0/Android权限被拒的问题
核心原因
从Android 10(API 29)开始引入的**分区存储(Scoped Storage)**限制了应用对外部存储的访问,/storage/emulated/0/Android属于系统保护目录,常规的READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE权限无法直接访问。X-plore这类文件管理器能正常访问,是因为它们完成了MANAGE_EXTERNAL_STORAGE特殊权限的申请与系统级授权流程。
具体解决方案
1. 完善Manifest配置
确保AndroidManifest.xml的权限声明和版本适配正确:
<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" /> <!-- Android 10及以下兼容分区存储限制 --> <application ... android:requestLegacyExternalStorage="true">
WRITE_EXTERNAL_STORAGE在API 29+已废弃,添加maxSdkVersion="28"避免冗余声明。requestLegacyExternalStorage="true"可让应用在Android 10上暂时绕过分区存储限制。
2. 运行时权限申请
(1)常规读写权限(API < 30)
针对Android 11以下设备,需在运行时主动申请READ_EXTERNAL_STORAGE:
if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.ReadExternalStorage) != Permission.Granted) { ActivityCompat.RequestPermissions(this, new string[] { Manifest.Permission.ReadExternalStorage }, 100); }
(2)MANAGE_EXTERNAL_STORAGE特殊权限(API >= 30)
Android 11及以上版本中,MANAGE_EXTERNAL_STORAGE属于特殊权限,无法通过常规弹窗申请,必须引导用户到系统设置手动开启:
if (Build.VERSION.SdkInt >= BuildVersionCodes.R) { if (!Environment.IsExternalStorageManager) { Intent intent = new Intent(Settings.ActionManageAppAllFilesAccessPermission); intent.Data = Android.Net.Uri.Parse($"package:{PackageName}"); StartActivityForResult(intent, 200); } }
需在OnActivityResult或OnRequestPermissionsResult中校验权限是否成功授予,再执行文件遍历逻辑。
3. 代码优化建议
在递归遍历逻辑中增加权限校验,避免无权限时触发异常:
private void RecursivelyListFilesAndDirectories(string directoryPath, List<string> fileList) { try { // 先校验当前路径是否可读 Java.IO.File targetDir = new Java.IO.File(directoryPath); if (!targetDir.CanRead()) { return; } string[] files = System.IO.Directory.GetFiles(directoryPath); string[] directories = System.IO.Directory.GetDirectories(directoryPath); fileList.AddRange(files); foreach (string subDir in directories) { fileList.Add(subDir); RecursivelyListFilesAndDirectories(subDir, fileList); } } catch (UnauthorizedAccessException ex) { Console.WriteLine($"无权限访问路径: {directoryPath} | 错误信息: {ex.Message}"); } catch (Exception ex) { Console.WriteLine($"遍历出错: {ex.Message}"); } }
4. 注意事项
- Google Play对
MANAGE_EXTERNAL_STORAGE权限审核严格,仅文件管理器类应用易通过审核,普通应用优先使用分区存储API(如MediaStore、SAF)访问文件。 - 测试时优先使用真实设备,部分模拟器的权限逻辑与真机存在差异。
内容的提问来源于stack exchange,提问作者jca
相关产品推荐
相关产品推荐

