如何在Xamarin.Forms安卓端实现全文件夹文件浏览及CSV读写
嘿,我来帮你捋捋这个问题!你遇到的其实是Android 10及以上版本引入的**分区存储(Scoped Storage)**限制,加上Plugin.FilePicker的默认设置导致的。咱们一步步来调整:
从Android 10开始,系统收紧了外部存储的访问权限:默认情况下,应用只能访问自己的私有目录和系统指定的公共目录(比如Download、Pictures)。如果要访问SD卡根目录、自定义文件夹这类非公共目录,就必须借助存储访问框架(SAF)——而Plugin.FilePicker默认并没有启用这个模式,所以只能摸到Download文件夹。
首先确保你用的是最新版的Plugin.FilePicker(旧版本可能没有SAF支持),然后按下面的步骤改:
2.1 更新AndroidManifest.xml
在你的Android项目的AndroidManifest.xml里添加必要的权限和配置:
<!-- 读取外部存储权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Android 9及以下需要写入权限,10+不用 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" /> <!-- Android 11+如果要申请全存储访问(谨慎使用),加这个 --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" android:minSdkVersion="30" /> <!-- 在application标签里添加这个,兼容Android 10的旧存储模式 --> <application android:requestLegacyExternalStorage="true"> <!-- 你的其他application配置 --> </application>
2.2 调用FilePicker时启用SAF模式
在Xamarin.Forms的代码里,调用FilePicker时指定UseAdvancedPicker=true(这个参数是Plugin.FilePicker用来启用SAF的,不同版本可能略有差异,你可以核对下插件文档):
var pickOptions = new PickOptions { PickerTitle = "选择CSV文件", // 启用SAF,打开系统文件浏览器,支持访问更多目录 UseAdvancedPicker = true }; var selectedFile = await FilePicker.Default.PickAsync(pickOptions); if (selectedFile != null) { // 读取文件流 using var stream = await selectedFile.OpenReadAsync(); // 你的CSV读取逻辑 }
如果你的应用要支持Android 11(API 30)及以上,requestLegacyExternalStorage就不再生效了,这时候有两种选择:
- 推荐:用SAF让用户手动选择:这是Google官方推荐的方式,不需要申请全存储权限,用户通过系统文件浏览器选择文件/目录后,应用就能获得对应访问权限,完全符合新的存储规则。上面的
UseAdvancedPicker=true就是走这个流程。 - 慎用:申请全存储访问权限:如果你的应用是文件管理器、备份工具这类必须访问整个存储的类型,可以申请
MANAGE_EXTERNAL_STORAGE权限,但Google对这个权限的审核非常严格,非必要不建议用。代码里要引导用户手动授权:if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.R) { if (!Android.OS.Environment.IsExternalStorageManager) { var intent = new Intent(Android.Provider.Settings.ActionManageAppAllFilesAccessPermission); intent.AddFlags(Android.Content.ActivityFlags.NewTask); intent.SetData(Android.Net.Uri.Parse($"package:{Android.App.Application.Context.PackageName}")); Android.App.Application.Context.StartActivity(intent); } }
如果需要把CSV写入到非应用私有目录,同样建议用SAF让用户选择保存位置,比如用Plugin.FilePicker的保存功能,或者Xamarin.Essentials的FileSaver,让用户通过系统界面选择保存路径,避免权限问题。
- 一定要在真机上测试,模拟器的存储权限逻辑和真机可能有差异;
- 确认Android项目的目标SDK版本设置为30及以上;
- 测试访问SD卡根目录、自定义文件夹,验证是否能正常选择文件。
内容的提问来源于stack exchange,提问作者D V

