Xamarin Forms访问图片目录遇权限拒绝及文件找不到问题求助
Android 11(API30)下Xamarin拍照后文件访问权限问题
我使用Xamarin.CommunityToolkit的Shutter()方法拍摄照片,触发MediaCaptured事件后尝试保存照片,但遇到以下问题:
- 硬编码路径写入公共Pictures目录时,始终抛出Access-Denied异常
- 使用Xamarin.Essentials的
FileSystem.AppDataDirectory写入应用私有目录后,在模拟器/Android/data/learningXamarin/下找不到files文件夹,仅能看到cache文件夹 - 尝试
Environment.SpecialFolder.LocalApplicationData路径也未成功
环境:Pixel5 Android11(API30)模拟器,已在AndroidManifest中配置相机、存储相关权限。
首次尝试代码(硬编码公共目录)
private async void MediaCaptured(object sender, MediaCapturedEventArgs e) { // 获取并显示图片 imgView.Source = e.Image; imgViewPanel.IsVisible = true; // 尝试写入公共Pictures目录 var photo = e.ImageData; var filename = "photo_test_01.png"; var filePath = "/storage/emulated/0/Pictures/" + filename; File.WriteAllBytes(filePath, photo); // 触发Access-Denied异常 }
问题原因分析
- Android 11分区存储限制:Android 10开始引入分区存储,Android 11进一步收紧权限。直接通过
File.WriteAllBytes写入公共存储目录(如Pictures)会被拒绝,即使申请了WRITE_EXTERNAL_STORAGE权限(该权限在Android 10+仅对媒体文件生效,且不能直接用File API操作)。 - 应用私有目录显示问题:
FileSystem.AppDataDirectory对应Android应用的/data/data/[包名]/files目录,模拟器的文件管理器默认可能不会显示这个路径,需要通过ADB命令或代码日志确认实际路径,而非仅依赖模拟器的文件浏览界面。
解决方案
方案1:使用MediaStore API写入公共Pictures目录(推荐)
针对Android 10+的媒体文件写入,应使用MediaStore API而非直接操作文件路径:
private async Task SavePhotoToPublicPictures(byte[] photoBytes, string filename) { var contentValues = new ContentValues(); contentValues.Put(MediaStore.Images.Media.Columns.DisplayName, filename); contentValues.Put(MediaStore.Images.Media.Columns.MimeType, "image/png"); // 指定Pictures下的子目录,避免和其他应用文件混杂 contentValues.Put(MediaStore.Images.Media.Columns.RelativePath, "Pictures/MyAppPhotos"); // 插入到媒体库 var uri = Android.App.Application.Context.ContentResolver.Insert(MediaStore.Images.Media.ExternalContentUri, contentValues); if (uri == null) return; // 写入字节流 using (var stream = Android.App.Application.Context.ContentResolver.OpenOutputStream(uri)) { await stream.WriteAsync(photoBytes, 0, photoBytes.Length); } }
方案2:写入应用私有目录(无需额外权限)
确认路径正确性,通过日志输出实际路径,而非依赖模拟器文件管理器:
private void SavePhotoToPrivateDir(byte[] photoBytes, string filename) { var filePath = Path.Combine(FileSystem.AppDataDirectory, filename); File.WriteAllBytes(filePath, photoBytes); // 输出路径到日志,方便通过ADB查看 Console.WriteLine($"照片已保存到私有目录:{filePath}"); }
可以通过ADB命令查看私有目录内容:
adb shell run-as com.yourapp.package ls /data/data/com.yourapp.package/files
权限配置补充
确保AndroidManifest中配置了必要权限:
<uses-permission android:name="android.permission.CAMERA" /> <!-- Android 9及以下需要WRITE_EXTERNAL_STORAGE --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" /> <!-- 读取媒体文件需要 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
如果必须访问所有文件(不推荐),可添加MANAGE_EXTERNAL_STORAGE权限,并在代码中引导用户手动开启权限。
内容的提问来源于stack exchange,提问作者APSys
相关产品推荐
相关产品推荐

