Android 13下.NET MAUI如何将图片保存到自定义相册文件夹
解决.NET MAUI拍照图片无法在系统相册显示的问题
问题核心
当前图片保存到了应用私有存储目录(/data/user/0/com.companyname.photov2/files/Pictures/GPV2/...),系统相册不会自动扫描应用私有目录下的文件,因此无法被识别显示。
解决方案
方案1:使用MediaStore API保存(符合Android Scoped Storage规范,推荐)
Android 10及以上引入了Scoped Storage限制,直接写入公共目录可能存在权限问题,通过MediaStore将图片插入系统媒体库,可自动在相册中显示:
using Android.Content; using Android.OS; using Android.Provider; using System.IO; using System.Threading.Tasks; public async Task SavePhotoToGallery(Xamarin.MediaGallery.Photo photo, int visitaId) { var context = Android.App.Application.Context; string fileName = $"{visitaId}_{DateTime.Now:yy_MM_dd_HH_mm_ss}.jpg"; // 配置MediaStore元数据 ContentValues values = new ContentValues(); values.Put(MediaStore.Images.ImageColumns.DisplayName, fileName); values.Put(MediaStore.Images.ImageColumns.MimeType, "image/jpeg"); if (Build.VERSION.SdkInt >= BuildVersionCodes.Q) { // Android 10+ 指定相对路径到Pictures/GPV2 values.Put(MediaStore.Images.ImageColumns.RelativePath, $"Pictures/GPV2"); values.Put(MediaStore.Images.ImageColumns.IsPending, 1); } else { // Android 9及以下直接指定公共存储路径 string publicPicturesDir = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures).AbsolutePath; string folderPath = Path.Combine(publicPicturesDir, "GPV2"); Directory.CreateDirectory(folderPath); string filePath = Path.Combine(folderPath, fileName); values.Put(MediaStore.Images.ImageColumns.Data, filePath); } // 插入到媒体库并获取文件URI var uri = context.ContentResolver.Insert(MediaStore.Images.Media.ExternalContentUri, values); // 将拍摄的图片写入媒体库 using (Stream sourceStream = await photo.OpenReadAsync()) using (Stream outputStream = context.ContentResolver.OpenOutputStream(uri)) { await sourceStream.CopyToAsync(outputStream); } // 标记文件为已完成(Android 10+) if (Build.VERSION.SdkInt >= BuildVersionCodes.Q) { values.Clear(); values.Put(MediaStore.Images.ImageColumns.IsPending, 0); context.ContentResolver.Update(uri, values, null, null); } // 将图片字节读取到vf.Foto(如果需要本地缓存) using (Stream inputStream = context.ContentResolver.OpenInputStream(uri)) using (MemoryStream ms = new MemoryStream()) { await inputStream.CopyToAsync(ms); vf.Foto = ms.ToArray(); } vf.Titulo = fileName; }
方案2:保存到公共目录后通知系统扫描
如果坚持直接写入公共存储目录,需切换路径到系统公共Pictures文件夹,再通知媒体库扫描新文件:
步骤1:修改保存路径
替换原私有路径为公共外部存储路径:
string publicPicturesDir; if (Build.VERSION.SdkInt >= BuildVersionCodes.Q) { publicPicturesDir = Android.OS.Environment.DirectoryPictures; } else { publicPicturesDir = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures).AbsolutePath; } var folderPath = Path.Combine(publicPicturesDir, "GPV2"); Directory.CreateDirectory(folderPath); string filePath = Path.Combine(folderPath, $"{vf.IdVisita}_{DateTime.Now:yy_MM_dd_HH_mm_ss}.jpg");
步骤2:保存后通知系统扫描
写入文件后发送广播或调用扫描接口:
// 写入图片到文件(原逻辑补充) using (Stream sourceStream = await photo.OpenReadAsync()) using (FileStream fileStream = new FileStream(filePath, FileMode.Create)) { await sourceStream.CopyToAsync(fileStream); } // 通知媒体库更新 if (Build.VERSION.SdkInt >= BuildVersionCodes.R) { MediaScannerConnection.ScanFile(context, new string[] { filePath }, null, null); } else { Intent mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile); mediaScanIntent.SetData(Android.Net.Uri.FromFile(new Java.IO.File(filePath))); context.SendBroadcast(mediaScanIntent); }
权限优化建议
- 移除
MANAGE_EXTERNAL_STORAGE权限:此权限用于访问所有文件,本需求无需开启,会增加权限申请复杂度。 - Android 13+仅需保留
CAMERA和READ_MEDIA_IMAGES权限,写入媒体库或公共目录无需额外写入权限。
内容的提问来源于stack exchange,提问作者Giorgio
相关产品推荐
相关产品推荐

