แชร์ผ่าน


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.

API

Find more Xamarin videos on Channel 9 and YouTube.