3

I'm using Xamarin Essentials MediaPicker (v1.7.3) on my Xamarin Forms 5 app and it just freezes and eventually crashes the app on iOS but works perfectly fine on Android.

My app uses the MVVM pattern so I have an ImageButton that's wired to a method in my view model and the code for that method looks like this:

async Task Add_Image_Tapped()
{
   try
   {
      var photosPermission = await Permissions.CheckStatusAsync<Permissions.Photos>();
      var cameraPermission = await Permissions.CheckStatusAsync<Permissions.Camera>();

      if (photosPermission != PermissionStatus.Granted || photosPermission != PermissionStatus.Restricted)
         photosPermission = await Permissions.RequestAsync<Permissions.Photos>();

      if (cameraPermission != PermissionStatus.Granted || cameraPermission != PermissionStatus.Restricted)
         cameraPermission = await Permissions.RequestAsync<Permissions.Camera>();

      if ((photosPermission == PermissionStatus.Granted
         || photosPermission == PermissionStatus.Restricted)
         && (cameraPermission == PermissionStatus.Granted
         || cameraPermission == PermissionStatus.Restricted))
         await HandleImagePicker();
   }
   catch(Exception e)
   {
      throw new Exception(e.Message);
   }
}

And if the permissions check out fine, here's the method that handles the image pick up:

private async Task HandleImagePicker()
{
   try
   {
      var filePath = string.Empty;
      var fileName = string.Empty;

      MainThread.BeginInvokeOnMainThread(() => {

         var result = MediaPicker.PickPhotoAsync(new MediaPickerOptions
         {
            Title = "Pick Image"
         }).Result;

         if (result == null)
            return;

         filePath = result.FullPath;
         fileName = result.FileName;

      });

      if (!string.IsNullOrEmpty(filePath) && !string.IsNullOrEmpty(fileName))
      {
         // Do something with the image
      }
   }
   catch(Exception e)
   {
      throw new Exception(e.Message);
   }
}

I'm using Xamarin Forms 5.0.0.2401, Xamarin Community Toolkit 2.0.2 and Xamarin Essentials 1.7.3. I also have the following permissions in my Info.plist:

<key>NSCameraUsageDescription</key>
<string>MyApp would like to access your camera</string>
<key>NSMicrophoneUsageDescription</key>
<string>MyApp would like to access your microphone</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>MyApp would like to access your photo library</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>MyApp would like to access your photo library</string>

I also initialize Xamarin Essentials in AppDelegate FinishedLaunching() method as below:

Xamarin.Essentials.Platform.Init(() => new UIViewController());

Any idea what maybe the issue here?

UPDATE:

The above code reflects the current code I have after making changes based on suggestions such as using the main thread.

Currently, if I run the app on iOS Simulator on a Mac, it literally hangs forever. Never throws an exception or crashes.

If I run it on a real device i.e. iPhone Xs, it will hang for quite a while and eventually crash the whole app.

As mentioned earlier, it all works perfectly fine on Android.

Sam
  • 26,817
  • 58
  • 206
  • 383

3 Answers3

2

Here are some suggestions

  1. Try to revert the method signature to the original one .

    private async void Image_Picker_Tapped(object sender, EventArgs e){}
    
  2. Wrap your code with Try Catch to see if there is any error information.

  3. Do not set any parameter while calling PickPhotoAsync .

    var result = await MediaPicker.PickPhotoAsync();
    
  4. Try to add await Task.Delay(100) before calling PickPhotoAsync.

ColeX
  • 14,062
  • 5
  • 43
  • 240
  • The MediaPicker was self closing immediately, then, I added `await Task.Delay(100);` and it worked. Thanks a lot ! – Bibimission Nov 17 '22 at 10:31
0

Can you show how you are requesting for user permissions to access the device storage.

Suggestion - add a check method for permissions check for every time you try to access the device storage. You can use Permissions.CrossPermissions plugin for it.

An sample for it would look like -

async Task Image_Picker_Tapped()
{
   if (await GetPhotoLibraryPermission())
   {
      var result = await MediaPicker.PickPhotoAsync(new MediaPickerOptions
      {
         Title = "Pick Image"
      };
   }
   // Handle the image
}
private async Task<bool> GetPhotoLibraryPermission()
        {
            PermissionStatus cameraPermissionStatus = await CrossPermissions.Current.CheckPermissionStatusAsync<CameraPermission>();
            if (cameraPermissionStatus != PermissionStatus.Granted)
            {
                cameraPermissionStatus = await CrossPermissions.Current.RequestPermissionAsync<CameraPermission>();
            }
            var storagePermissionStatus = await CrossPermissions.Current.RequestPermissionAsync<StoragePermission>();
            if (storagePermissionStatus != PermissionStatus.Granted)
            {
                storagePermissionStatus = await CrossPermissions.Current.RequestPermissionAsync<StoragePermission>();
            }
            return cameraPermissionStatus == PermissionStatus.Granted && storagePermissionStatus == PermissionStatus.Granted;
        }
Blu
  • 821
  • 4
  • 17
  • Interestingly, when I checked for permissions, it came back `unknown` even though in `Info.plist`, I ask for it. I implemented new code that would ask for permission if it's not already set to `granted`. It's still not working but now it seems to freeze up the app. – Sam May 10 '22 at 19:36
  • @Sam can you edit the question with detailed description with new issue you are facing with the code snippet, might be a case you missed a very minor thing which might cause that issue – Blu May 11 '22 at 05:15
0

Its important to use PickPhotoAsync with await.

This code probably traded your original hang for a different hang:

 var result = MediaPicker.PickPhotoAsync(new MediaPickerOptions
 {
    Title = "Pick Image"
 }).Result;

You need to switch to MainThread and start an async context.
Given that you are already in an async method, use a newer MainThread method, InvokeOnMainThreadAsync. AND add async inside the Invoke:

// Have "await" and "async" here.
await Device.InvokeOnMainThreadAsync(async () => {
    ...
    // HAVE "await" here.
    var result = await MediaPicker.PickPhotoAsync(new MediaPickerOptions
    {
        Title = "Pick Image"
    });   // DON'T use ".Result".

YES await/async, NO .Result.


If this still hangs, then please make a public github repo, containing a simple project that shows the hang, that can be built and run.

ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
  • With this change, it's no longer hanging but the media picker still doesn't launch and in the output, this is what I see `[Presentation] Attempt to present on (from ) whose view is not in the window hierarchy.` – Sam Jun 07 '22 at 04:44
  • This issue sounds very similar to this one: https://stackoverflow.com/questions/41241508/xamarin-forms-warning-attempt-to-present-on-whose-view-is-not-in-the-window – Sam Jun 07 '22 at 04:47
  • Here's another similar issue: https://stackoverflow.com/questions/56187423/attempt-to-present-xamarin-forms-platform-ios-modalwrapper-whose-view-is-not-in – Sam Jun 07 '22 at 05:18
  • Are you using AppShell? Or showing a `Modal` page? I have a vague idea that it might be necessary to switch back to MainPage, then call MediaPicker. – ToolmakerSteve Jun 08 '22 at 01:45
  • Yes, I’m using `AppShell` – Sam Jun 08 '22 at 03:33