Search code examples
xamarinxamarin.essentials

Geolocation.GetLastKnownLocationAsync() sometimes returns null


This is on iOS 12.1.4 on an iPhone 6s. Usually Geolocation.GetLastKnownLocationAsync() works but sometimes it doesn't. It's the exact same code but if I sit here and press my "get latitude and longitude" button over and over eventually Geolocation.GetLastKnownLocationAsync() spits out a null.

Do you know why this happens and how I might handle it? Perhaps put it in a loop that tries ten times, waiting a second between each try?

var location = await Essentials.Geolocation.GetLastKnownLocationAsync(); // works most of the time but sometimes it doesn't work.

This is my proposed work around:

Essentials.Location location = null;
for(var i = 0; i < 10; i++)
{
    location = await Essentials.Geolocation.GetLastKnownLocationAsync();
    if(location == null)
    {
        Thread.Sleep(1000);
    }
    else
    {
        break;
    }
}

Solution

  • First, it is really bad practice to use Thread.Sleep (unless you are not on the main/UI loop) as you are hanging the run loop, if you really need a delay, use await Task.Delay(.... Also CLLocationManager on iOS is running on the main loop and if you are blocking it, the message pump is hung and the location manager manager can not report back to the app.

    "Spamming" CLLocationManager.Location (which Essentials is using on iOS) can (and will) result in null returns due to OS rate limiting updates (mainly a battery conservation measure) and if the OS is powering up the GPS radio to update its location, this method will timeout on from the OS, thus report nil back to GetLastKnownLocationAsync and thus you get a return of null.

    CLLocationManager.Location on iOS is meant for a quick low-power return from the OS to app as is updated upon app launch, device reboot, etc... not every time you call it.

    You can get the last known location of the device by calling the GetLastKnownLocationAsync method. This is often faster then doing a full query, but can be less accurate.

    Otherwise you should be using GetLocationAsync in order to do a full GPS power up to obtain an updated accurate location.

    To query the current device's location coordinates, the GetLocationAsync can be used. It is best to pass in a full GeolocationRequest and CancellationToken since it may take some time to get the device's location.

    Typically I recommend using GetLastKnownLocationAsync as a quick way to get the general area of the user knowing that this might also return null. Then proceed to do a GetLocationAsync (passing both a GeolocationRequest and CancellationToken instance) in the background and update the app accordingly upon the more accurate and recent position.

    re: https://learn.microsoft.com/en-us/xamarin/essentials/geolocation?tabs=ios