5

I'm currently using the latest version of Xamarin.Forms (4.5.0.617) and Xamarin.Essentials (1.5.2).

I have a dependency injected service which is responsible for getting access to phone contacts, it's effectively a wrapper around the Xamarin.Essentials permissions code. I need to guarantee that the code is executed on the UI thread to avoid exceptions. I've got as far as the below code, however, it isn't working as i'd expect. In my app, the permissions popup appears and offers me the choice allow/deny but then all code after RequestAsync fails to execute like a response is never officially returned. The next time I run the app, it works straight away (so presumably permission in the background has been correctly recorded).

public async Task<bool> RequestAccessPhoneContacts()
{
    PermissionStatus status = PermissionStatus.Denied;

    status = await MainThread.InvokeOnMainThreadAsync<PermissionStatus>(async () =>
    {
        return await Permissions.RequestAsync<Permissions.ContactsRead>();
    });

    return (status == PermissionStatus.Granted);
}

I'm not sure if i've caused an issue with the way i'm trying to force the code onto the UI thread or whether i'm using the async code incorrectly... or (least likely) whether it's a bug in the Xamarin.Essentials Permissions code. I've only seen this behaviour on Android at the moment, but I haven't tested it on any others.

Any help greatly appreciated :)

thanks!

Brooky
  • 138
  • 1
  • 7
  • I don't think you need to call RequestAsync in MainThread. What exceptions do you get? – nevermore Apr 17 '20 at 07:58
  • 1
    This is the exception I receive - Xamarin.Essentials.PermissionException: 'Permission request must be invoked on main thread.' {Xamarin.Essentials.PermissionException: Permission request must be invoked on main thread. at Xamarin.Essentials.Permissions+BasePlatformPermission.RequestAsync () [0x0020d] in d:\a\1\s\Xamarin.Essentials\Permissions\Permissions.android.cs:118 } – Brooky Apr 17 '20 at 09:41

2 Answers2

3

I had a similar issue when I called current location using Xamarin.Essentials. I got this exception:

Xamarin.Essentials.PermissionException: 'Permission request must be invoked on main thread.'

& this helped me resolve.

  1. Call current location from main thread

     private Task<Location> GetLastKnownLocation()
     {
         var locationTaskCompletionSource = new TaskCompletionSource<Location>();
    
         Device.BeginInvokeOnMainThread(async () =>
         {
             locationTaskCompletionSource.SetResult(await Geolocation.GetLastKnownLocationAsync());
         });
    
         return locationTaskCompletionSource.Task;
     }
    
  2. And call above method inside Try catch block & also use configure await false

     private async Task ExecuteGetGeoLocationCommand()
     {
         try
         {
             var location = await GetLastKnownLocation().ConfigureAwait(false);
    
         }
         catch (FeatureNotSupportedException fnsEx) {} 
         catch (Exception ex){}
     }
    
The Backer
  • 568
  • 1
  • 3
  • 10
2

Turns out I hadn't followed the documentation properly when setting this up.

After adding this into my main activity, everything kicks back to life.

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Android.Content.PM.Permission[] grantResults)
{
    Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);

    base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}

This information came out of me raising a bug on the Xamarin.Essentials github - https://github.com/xamarin/Essentials/issues/1227

Brooky
  • 138
  • 1
  • 7
  • You can mark this answer which will help more people with same problem:). – nevermore Apr 20 '20 at 01:27
  • 1
    Sorry, this does not work for me. Default Xamarin app template already contains this OnRequestPermissionsResult() method in MainActivity.cs but this does not help at all. :-( – dmitry_bond Jul 23 '20 at 08:34