Xamarin.Essentials: географическое расположение

Класс Geolocation предоставляет API для получения текущих геолокационных координат устройства.

Начало работы

Чтобы начать использовать этот API, ознакомьтесь с руководством по началу работы с Xamarin.Essentials, чтобы правильно настроить и установить библиотеку в проектах.

Чтобы проверить функциональность класса Geolocation, нужно создать описанную ниже конфигурацию для конкретной платформы:

Требуются разрешения Coarse и Fine Location, которые следует настроить в проекте Android. Кроме того, если приложение предназначено для платформы Android 5.0 (уровень API 21) или более поздней версии, в файле манифеста необходимо объявить, что приложение использует аппаратные возможности. Для этого можно применить любой из следующих методов:

Откройте файл AssemblyInfo.cs в папке Свойства и добавьте в него:

[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)]

Или обновите манифест Android:

Откройте файл AndroidManifest.xml в папке Properties и добавьте приведенный ниже код в узел manifest:

<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" />

Или щелкните правой кнопкой мыши проект Android и откройте свойства проекта. В разделе Манифест Android найдите область Требуемые разрешения: и установите флажок для разрешений ACCESS_COARSE_LOCATION и ACCESS_FINE_LOCATION. Это действие автоматически обновляет файл AndroidManifest.xml.

Если приложение предназначено для Android 10 Q (API уровня 29 или более поздней версии) и запрашивает LocationAlways, необходимо также добавить следующее разрешение в AssemblyInfo.cs:

[assembly: UsesPermission(Manifest.Permission.AccessBackgroundLocation)]

Или непосредственно в AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

Рекомендуется читать документацию Android по фоновому расположению , так как необходимо учитывать множество ограничений.

Этот API использует разрешения среды выполнения для Android. Убедитесь, что набор Xamarin.Essentials полностью инициализирован и в вашем приложении настроена обработка разрешений.

В MainLauncher проекта Android или в любом запущенном действии Activity необходимо инициализировать Xamarin.Essentials в методе OnCreate:

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
    //...
}    

Для обработки на устройстве Android разрешений среды выполнения Xamarin.Essentials нужно получить любой OnRequestPermissionsResult. Добавьте следующий код во все классы Activity:

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);
}

Использование геолокации

Добавьте ссылку на Xamarin.Essentials в своем классе:

using Xamarin.Essentials;

В API геолокации пользователю также будет предложено предоставить разрешения при необходимости.

Вы можете получить последнее известное расположение устройства, вызвав метод GetLastKnownLocationAsync. Зачастую эта операция быстрее, чем выполнение всего запроса, но не так точна и может вернуть null, если расположение для кэширования отсутствует.

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
}

Чтобы запросить текущие координаты расположения устройства, можно использовать GetLocationAsync. Лучше всего передать полный GeolocationRequest и CancellationToken, так как получение расположения устройства может занять некоторое время.

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();
}

Не все значения могут быть доступны, так как каждое устройство запрашивает географическое расположение через разных поставщиков. Например, свойство Altitude может быть равно null, может иметь значение 0 или положительное значение, которое представляет собой высоту в метрах над уровнем моря. В число других значений, которые могут отсутствовать, входят Speed и Course.

Точность геолокации

В следующей таблице приведены сведения о точности для каждой платформы:

Наиболее низкий

Платформа Расстояние (в метрах)
Android 500
iOS 3000
UWP 1000–5000

Низкая

Платформа Расстояние (в метрах)
Android 500
iOS 1000
UWP 300–3000

Medium (по умолчанию)

Платформа Расстояние (в метрах)
Android 100–500
iOS 100
UWP 30–500

Высокая

Платформа Расстояние (в метрах)
Android 0–100
iOS 10
UWP <= 10

Лучшее

Платформа Расстояние (в метрах)
Android 0–100
iOS ~0
UWP <= 10

Определение расположений макетов

Некоторые устройства могут возвращать расположение макетов от поставщика или приложения, которое предоставляет расположения макетов. Его можно определить с помощью IsFromMockProvider на любом 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
    }
}

Расстояние между двумя расположениями

Классы Location и LocationExtensions определяют методы CalculateDistance, которые дают возможность вычисления расстояния между двумя географическими расположениями. При расчете не учитываются дороги или другие пути. Это самое короткое расстояние между двумя точками на поверхности Земли, также известное как расстояние по дуге большого круга или, говоря простым языком, расстояние напрямик.

Приведем пример:

Location boston = new Location(42.358056, -71.063611);
Location sanFrancisco = new Location(37.783333, -122.416667);
double miles = Location.CalculateDistance(boston, sanFrancisco, DistanceUnits.Miles);

В конструкторе Location аргументы широты и долготы указаны в следующем порядке. Положительные значения широты находятся к северу от экватора, а положительные значения долготы — к востоку от нулевого меридиана. Используйте последний аргумент CalculateDistance, чтобы указать единицы измерения: мили или километры. Класс UnitConverters также определяет методы KilometersToMiles и MilesToKilometers для преобразования между двумя единицами измерения.

Различия платформ

Высота на каждой платформе вычисляется по-разному.

В Android высота, если она доступна, возвращается в виде высоты над нормальным эллипсоидом всемирной геодезической системы координат в метрах. Если в этом расположении нет высоты, возвращается 0,0.

API

Другие видео о Xamarin см. на Channel 9 и YouTube.