2

GetLocationAsync fails on my Xamarin.Forms app.

I've got the latest Xamarin.Essentials nuget package.

I've set the necessary permissions in the info.plist.

I am calling this from my ViewModel.

The call is super simple:

var location = await Geolocation.GetLastKnownLocationAsync();

but it's both failing AND failing to prompt a user permission dialog even though my info.plist has been setup correctly with: NSLocationWhenInUseUsageDescription Insert reason

I'm asking and answering this question because it was a head scratcher, and I wasn't exactly sure what to be searching for or what the issue was.

My various searches pointed to many related issues but nothing that actually gets to the main problem.

The closest I got was actually this issue on the Essentials github page: https://github.com/xamarin/Essentials/issues/634

Andrew Chung
  • 417
  • 4
  • 15

2 Answers2

3

This answer is inspired by Xamarin/Azure evangelist, Brandon Minnick --> take a look at his project where he handles a similar situation with the following code:

So what can we take away from the above? If you look at the context, he has connected his Views with his ViewModels in MVVM style. However, various libraries require that certain methods be called from the Main thread. This is the essence of the issue, and this is what this code can solve.

So to adopt the above code for the geolocation issue addressed in the question, I did the following:

Task<Xamarin.Essentials.Location> GetLocationFromPhone()
{

    var locationTaskCompletionSource = new TaskCompletionSource<Xamarin.Essentials.Location>();

    Device.BeginInvokeOnMainThread(async () =>
    {
        locationTaskCompletionSource.SetResult(await Geolocation.GetLastKnownLocationAsync());
    });

    return locationTaskCompletionSource.Task;
}

I'm using the above from my ViewModel from within a Task. Something like the following.

async Task ExecuteGetGeoLocationCommand()
{
    try
    {
        var locationFromPhone = await GetLocationFromPhone().ConfigureAwait(false);

        if (locationFromPhone is null)
            return;

        _location = locationFromPhone;

        if (_location != null)
        {
            Console.WriteLine($"Latitude: {_location.Latitude}, Longitude {_location.Longitude}, Altitude: {_location.Altitude}");
        } 
        else
        {
            Console.WriteLine($"Exiting geolocation");
        }
        catch (FeatureNotSupportedException fnsEx)
        {
        }
        catch (Exception ex)
        {
        }
    }
}

I hope it's helpful to someone else!

Brandon Minnick
  • 13,342
  • 15
  • 65
  • 123
Andrew Chung
  • 417
  • 4
  • 15
0

If you're using Xamarin.Essentials and aren't being prompted for permission on Android, make sure you've added all the necessary code to the Android Main Activity.

See https://learn.microsoft.com/en-us/xamarin/essentials/get-started?tabs=windows%2Candroid for details.

From the docs:

protected override void OnCreate(Bundle savedInstanceState) {
    //...
    base.OnCreate(savedInstanceState);
    Xamarin.Essentials.Platform.Init(this, savedInstanceState); // add this line to your code, it may also be called: bundle
    //...

and

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

    base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
Auri Rahimzadeh
  • 2,133
  • 15
  • 21