dimonovdd / Xamarin.MediaGallery

This plugin is designed to picking and save images and video files from native gallery of Android and iOS devices and capture photos
MIT License
148 stars 18 forks source link

SaveAsync not working on iOS or Android #97

Closed lobbo232 closed 2 years ago

lobbo232 commented 2 years ago

Description

I am having some trouble to get SaveAsync working on iOS and Android. I am trying to take a photo, and then save the photo to the gallery too.

When calling SaveAsync with the path of a photo recently taken using CapturePhotoAsync in the Xamarin.Forms shared project, it throws an exception on both iOS and Android/

Actual Behavior

SaveAsync iOS exception:

{Foundation.NSErrorException: Error Domain=PHPhotosErrorDomain Code=-1 "(null)"
  at NativeMedia.MediaGallery.PhotoLibraryPerformChanges (System.Action action) [0x000ac] in <cb2ee5d4eb154dc9baa4ecea7ba18b93>:0 
  at NativeMedia.MediaGallery.PlatformSaveAsync (NativeMedia.MediaFileType type, System.String filePath) [0x000aa] in <cb2ee5d4eb154dc9baa4ecea7ba18b93>:0 
  at NativeMedia.MediaGallery.SaveAsync (NativeMedia.MediaFileType type, System.String filePath) [0x000f5] in <cb2ee5d4eb154dc9baa4ecea7ba18b93>:0 
  at Inspct.Services.DataService.SaveToGallery (System.String filePath) [0x00106] in C:\CODE\CPL\INSPCTXamarinApp\InspctXamarinApp\Inspct\Services\DataService.cs:190 
  at Inspct.Services.DataService.TakeNewPhoto (Inspct.Helpers.GlobalEnums+DataTableTypes tableType, System.Guid sourceID, System.Nullable`1[T] secondaryID, System.String fileName) [0x002b0] in C:\CODE\CPL\INSPCTXamarinApp\InspctXamarinApp\Inspct\Services\DataService.cs:141 
  at Inspct.Services.InspectionsService.AddInspectionDataAttachment (Inspct.ViewModels.Inspections.FieldTypes.FieldViewModel fieldViewModel) [0x004c1] in C:\CODE\CPL\INSPCTXamarinApp\InspctXamarinApp\Inspct\Services\InspectionsService.cs:999 }

SaveAsync Android exception:

{Java.Lang.IllegalArgumentException: MIME type application/octet-stream cannot be inserted into content://media/external/images/media; expected MIME type under image/*
  at Java.Interop.JniEnvironment+InstanceMethods.CallNonvirtualObjectMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x0008e] in <1959115d56f8444789986cf39185638c>:0 
  at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeNonvirtualObjectMethod (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x0001f] in <1959115d56f8444789986cf39185638c>:0 
  at Android.Content.ContentResolver.Insert (Android.Net.Uri url, Android.Content.ContentValues values) [0x00049] in /Users/builder/azdo/_work/2/s/xamarin-android/src/Mono.Android/obj/Release/monoandroid10/android-30/mcw/Android.Content.ContentResolver.cs:1127 
  at NativeMedia.MediaGallery.PlatformSaveAsync (NativeMedia.MediaFileType type, System.IO.Stream fileStream, System.String fileName) [0x00150] in <04e7edd214f44f6f8ccb9794e517ed6a>:0 
  at NativeMedia.MediaGallery.PlatformSaveAsync (NativeMedia.MediaFileType type, System.String filePath) [0x0008f] in <04e7edd214f44f6f8ccb9794e517ed6a>:0 
  at NativeMedia.MediaGallery.SaveAsync (NativeMedia.MediaFileType type, System.String filePath) [0x000f5] in <04e7edd214f44f6f8ccb9794e517ed6a>:0 
  at Inspct.Services.DataService.SaveToGallery (System.String filePath) [0x00106] in C:\CODE\CPL\INSPCTXamarinApp\InspctXamarinApp\Inspct\Services\DataService.cs:190 
  at Inspct.Services.DataService.TakeNewPhoto (Inspct.Helpers.GlobalEnums+DataTableTypes tableType, System.Guid sourceID, System.Nullable`1[T] secondaryID, System.String fileName) [0x002b0] in C:\CODE\CPL\INSPCTXamarinApp\InspctXamarinApp\Inspct\Services\DataService.cs:141 
  at Inspct.Services.InspectionsService.AddInspectionDataAttachment (Inspct.ViewModels.Inspections.FieldTypes.FieldViewModel fieldViewModel) [0x004c1] in C:\CODE\CPL\INSPCTXamarinApp\InspctXamarinApp\Inspct\Services\InspectionsService.cs:999 
  --- End of managed Java.Lang.IllegalArgumentException stack trace ---
java.lang.IllegalArgumentException: MIME type application/octet-stream cannot be inserted into content://media/external/images/media; expected MIME type under image/*
    at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:172)
    at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:142)
    at android.content.ContentProviderProxy.insert(ContentProviderNative.java:549)
    at android.content.ContentResolver.insert(ContentResolver.java:2149)
    at android.content.ContentResolver.insert(ContentResolver.java:2111)
    at mono.java.lang.RunnableImplementor.n_run(Native Method)
    at mono.java.lang.RunnableImplementor.run(RunnableImplementor.java:30)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:223)
    at android.app.ActivityThread.main(ActivityThread.java:7656)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
}

Expected behaviour

The image to be saved to the gallery and not throw an exception.

Steps to reproduce the behaviour

var photo = await MediaGallery.CapturePhotoAsync();
if (photo != null)
{
    string fileName = string.Format("INSPCT_{0}_{1}{2}", photo.NameWithoutExtension, DateTime.Now.Ticks.GetHashCode().ToString("X"), photo.Extension);
    string newFileLocation = Path.Combine(FilesDirectory, fileName);

    using (FileStream fileStream = File.OpenWrite(newFileLocation))
    {
        await (await photo.OpenReadAsync()).CopyToASync(fileStream);
    }

    photo.Dispose();

    var status = await Permissions.RequestAsync<SaveMediaPermission>();
    if (status == PermissionStatus.Granted)
    {
        await MediaGallery.SaveAsync(MediaFileType.Image, filePath); // throws exception
    }
}

Screenshots or Videos

Reproduction Link

Configuration

lobbo232 commented 2 years ago

Any devs or community members still active on this project? @dimonovdd @catchertinator

dimonovdd commented 2 years ago

Hello. This works great in sample project. Are you sure you are doing everything as described in the readme?

lobbo232 commented 2 years ago

Hello @dimonovdd,

I have attached a sample project for you to recreate the issue. Xam_savetogallery_not_working.zip

The SavePhotoFile method performs some post processing which I've removed in the sample for simplicity as it didn't effect the result I was getting.

Curiously, if I exclude the processing method entirely and save the photo result directly from it's own stream then it does work, but that doesn't allow me to process the file. await MediaGallery.SaveAsync(MediaFileType.Image, await photo.OpenReadAsync(), "test.png"); // works but skips processing

dimonovdd commented 2 years ago

I think you just need to add a dot.

$"INSPCT_{photo.NameWithoutExtension}_{DateTime.Now.Ticks.GetHashCode():X}.{photo.Extension}"

image

lobbo232 commented 2 years ago

Rookie mistake... thank you.