Search code examples
c#androidiosmaui

Android 13 How to save image in galery .Net MAUI


I'm creating a project in .Net MAUI that takes photos and I would like to know how can I save it in a gallery by creating a folder.

I've seen that Google has changed its permissions.

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<!-- Required only if your app needs to access images or photos that other apps created -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<!-- Required only if your app needs to access videos that other apps created -->
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<queries>
    <intent>
        <action android:name="android.media.action.IMAGE_CAPTURE" />
    </intent>
</queries>

This is the code:

string sGpath = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);

// Crear la ruta completa del archivo
var folderPath = Path.Combine(sGpath, "GPV2");

photo.FileName = $ "{vf.IdVisita}_{DateTime.Now:yy_MM_dd_HH_mm_ss}.jpg";
string uniqueFileName = $ "{vf.IdVisita}_{DateTime.Now:yy_MM_dd_HH_mm_ss}.jpg";

string filePath = Path.Combine(folderPath, photo.FileName);

if (!Directory.Exists(folderPath)) {
  Directory.CreateDirectory(folderPath);
}

using Stream sourceStream = await photo.OpenReadAsync();

Console.WriteLine($ "Archivo guardado en {filePath}");

vf.Titulo = uniqueFileName;
using(FileStream fileStream = File.OpenRead(filePath)) {
  vf.Foto = ReadFully(fileStream);
}

The path in which it is saved for me is

/data/user/0/com.companyname.photov2/files/Pictures/GPV2/1_24_05_30_10_53_48.jpg

Even with that it doesn't keep me in gallery, how can I do it?


Solution

  • You can use the following code to save the image stream to gallery of your android device.

        public static class ImageSaveHelper
        {
            public static async Task SaveImage(Stream imageStream)
            {
                using var stream = imageStream;
                using var memoryStream = new MemoryStream();
                stream.CopyTo(memoryStream);
    
                stream.Position = 0;
                memoryStream.Position = 0;
    
    #if ANDROID
    var context = Platform.CurrentActivity;
    
        if (OperatingSystem.IsAndroidVersionAtLeast(29))
        {
            Android.Content.ContentResolver resolver = context.ContentResolver;
            Android.Content.ContentValues contentValues = new();
            contentValues.Put(Android.Provider.MediaStore.IMediaColumns.DisplayName, "image.png");
            contentValues.Put(Android.Provider.MediaStore.IMediaColumns.MimeType, "image/png");
            contentValues.Put(Android.Provider.MediaStore.IMediaColumns.RelativePath, "DCIM/" + "image");
            Android.Net.Uri imageUri = resolver.Insert(Android.Provider.MediaStore.Images.Media.ExternalContentUri, contentValues);
               
            var os = resolver.OpenOutputStream(imageUri);
            Android.Graphics.BitmapFactory.Options options = new();
            options.InJustDecodeBounds = true;
            var bitmap = Android.Graphics.BitmapFactory.DecodeStream(stream);
            bitmap.Compress(Android.Graphics.Bitmap.CompressFormat.Png, 100, os);
            os.Flush();
            os.Close();
        }
        else
        {
            Java.IO.File storagePath = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures);
            string path = System.IO.Path.Combine(storagePath.ToString(), "image.png");
            System.IO.File.WriteAllBytes(path, memoryStream.ToArray());
            var mediaScanIntent = new Android.Content.Intent(Android.Content.Intent.ActionMediaScannerScanFile);
            mediaScanIntent.SetData(Android.Net.Uri.FromFile(new Java.IO.File(path)));
            context.SendBroadcast(mediaScanIntent);
        }
    
    #endif
            }
    
        }
    

    Note:

    How Can I request storage acces ? with Permissions.CheckStatusAsync<Permissions.Media>()? This doesn't work

    You need to add the following permissions if you want to save and read image to Gallery not Permissions.Media.

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="31" />
    

    From document Permissions, we know that permission Permissions.Media will always return Granted when checked or requested.

    And you also need the following api on the maui:

    PermissionStatus statusread = await Permissions.RequestAsync<Permissions.StorageRead>();
    PermissionStatus statuswrite = await Permissions.RequestAsync<Permissions.StorageWrite>();