Xamarin.Essentials: Geolocation
The Geolocation class provides APIs to retrieve the device's current geolocation coordinates.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly installed and set up in your projects.
To access the Geolocation functionality, the following platform-specific setup is required:
Coarse and Fine Location permissions are required and must be configured in the Android project. Additionally, if your app targets Android 5.0 (API level 21) or higher, you must declare that your app uses the hardware features in the manifest file. This can be added in the following ways:
Open the AssemblyInfo.cs file under the Properties folder and add:
[assembly: UsesPermission(Android.Manifest.Permission.AccessCoarseLocation)]
[assembly: UsesPermission(Android.Manifest.Permission.AccessFineLocation)]
[assembly: UsesFeature("android.hardware.location", Required = false)]
[assembly: UsesFeature("android.hardware.location.gps", Required = false)]
[assembly: UsesFeature("android.hardware.location.network", Required = false)]
Or update the Android manifest:
Open the AndroidManifest.xml file under the Properties folder and add the following inside of the manifest node:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.location" android:required="false" />
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
<uses-feature android:name="android.hardware.location.network" android:required="false" />
Or right-click on the Android project and open the project's properties. Under Android Manifest find the Required permissions: area and check the ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION permissions. This will automatically update the AndroidManifest.xml file.
If your application is targeting Android 10 - Q (API Level 29 or higher) and is requesting LocationAlways, you must also add the following permission into AssemblyInfo.cs:
[assembly: UsesPermission(Manifest.Permission.AccessBackgroundLocation)]
Or directly into your AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
It is recommended to read Android documentation on background location updates as there are many restrictions that need to be considered.
This API uses runtime permissions on Android. Please ensure that Xamarin.Essentials is fully initialized and permission handling is setup in your app.
In the Android project's MainLauncher
or any Activity
that is launched Xamarin.Essentials must be initialized in the OnCreate
method:
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
//...
}
To handle runtime permissions on Android, Xamarin.Essentials must receive any OnRequestPermissionsResult
. Add the following code to all Activity
classes:
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);
}
Using Geolocation
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
The Geolocation API will also prompt the user for permissions when necessary.
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 and may return null
if no cached location exists.
try
{
var location = await Geolocation.GetLastKnownLocationAsync();
if (location != null)
{
Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude: {location.Altitude}");
}
}
catch (FeatureNotSupportedException fnsEx)
{
// Handle not supported on device exception
}
catch (FeatureNotEnabledException fneEx)
{
// Handle not enabled on device exception
}
catch (PermissionException pEx)
{
// Handle permission exception
}
catch (Exception ex)
{
// Unable to get 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.
CancellationTokenSource cts;
async Task GetCurrentLocation()
{
try
{
var request = new GeolocationRequest(GeolocationAccuracy.Medium, TimeSpan.FromSeconds(10));
cts = new CancellationTokenSource();
var location = await Geolocation.GetLocationAsync(request, cts.Token);
if (location != null)
{
Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude: {location.Altitude}");
}
}
catch (FeatureNotSupportedException fnsEx)
{
// Handle not supported on device exception
}
catch (FeatureNotEnabledException fneEx)
{
// Handle not enabled on device exception
}
catch (PermissionException pEx)
{
// Handle permission exception
}
catch (Exception ex)
{
// Unable to get location
}
}
protected override void OnDisappearing()
{
if (cts != null && !cts.IsCancellationRequested)
cts.Cancel();
base.OnDisappearing();
}
Note all values may be available due to how each device queries geolocation through different providers. For example, the Altitude
property might be null
, have a value of 0, or have a positive value, which is in meters above sea level. Other values that may not be present include Speed
and Course
.
Geolocation Accuracy
The following table outlines accuracy per platform:
Lowest
Platform | Distance (in meters) |
---|---|
Android | 500 |
iOS | 3000 |
UWP | 1000 - 5000 |
Low
Platform | Distance (in meters) |
---|---|
Android | 500 |
iOS | 1000 |
UWP | 300 - 3000 |
Medium (Default)
Platform | Distance (in meters) |
---|---|
Android | 100 - 500 |
iOS | 100 |
UWP | 30-500 |
High
Platform | Distance (in meters) |
---|---|
Android | 0 - 100 |
iOS | 10 |
UWP | <= 10 |
Best
Platform | Distance (in meters) |
---|---|
Android | 0 - 100 |
iOS | ~0 |
UWP | <= 10 |
Detecting Mock Locations
Some devices may return a mock location from the provider or by an application that provides mock locations. You can detect this by using the IsFromMockProvider
on any Location
.
var request = new GeolocationRequest(GeolocationAccuracy.Medium);
var location = await Geolocation.GetLocationAsync(request);
if (location != null)
{
if(location.IsFromMockProvider)
{
// location is from a mock provider
}
}
Distance between Two Locations
The Location
and LocationExtensions
classes define CalculateDistance
methods that allow you to calculate the distance between two geographic locations. This calculated distance does not take roads or other pathways into account, and is merely the shortest distance between the two points along the surface of the Earth, also known as the great-circle distance or colloquially, the distance "as the crow flies."
Here's an example:
Location boston = new Location(42.358056, -71.063611);
Location sanFrancisco = new Location(37.783333, -122.416667);
double miles = Location.CalculateDistance(boston, sanFrancisco, DistanceUnits.Miles);
The Location
constructor has latitude and longitude arguments in that order. Positive latitude values are north of the equator, and positive longitude values are east of the Prime Meridian. Use the final argument to CalculateDistance
to specify miles or kilometers. The UnitConverters
class also defines KilometersToMiles
and MilesToKilometers
methods for converting between the two units.
Platform Differences
Altitude is calculated differently on each platform.
On Android, altitude, if available, is returned in meters above the WGS 84 reference ellipsoid. If this location does not have an altitude then 0.0 is returned.