Поделиться через


Геолокация

Browse sample. Обзор примера

В этой статье описывается, как использовать интерфейс многоплатформенного приложения .NET (.NET MAUI). IGeolocation Этот интерфейс предоставляет API для получения текущих координат географического расположения устройства.

Реализация интерфейса по умолчанию IGeolocation доступна через Geolocation.Default свойство. Интерфейс IGeolocation и Geolocation класс содержатся в Microsoft.Maui.Devices.Sensors пространстве имен.

Начать

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

Необходимо указать необходимые или тонкие разрешения на расположение, а также настроить их в проекте Android.

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

  • Добавьте разрешение на основе сборки:

    Откройте файл Platform/Android/MainApplication.cs и добавьте следующие атрибуты сборки после using директив:

    [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 10 — Q (уровень API 29 или более поздней версии) и запрашивает LocationAlwaysего, необходимо также добавить этот запрос на разрешение:

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

    - или -

  • Обновите манифест Android:

    Откройте файл Platform/Android/AndroidManifest.xml и добавьте в узел следующее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 10 — Q (уровень API 29 или более поздней версии) и запрашивает LocationAlwaysего, необходимо также добавить этот запрос на разрешение:

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

    - или -

  • Обновите манифест Android в редакторе манифеста:

    В Visual Studio дважды щелкните файл Platform/Android/AndroidManifest.xml , чтобы открыть редактор манифеста Android. Затем в разделе "Необходимые разрешения" проверка указанные выше разрешения. Это действие автоматически обновляет файл AndroidManifest.xml.

Совет

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

Получение последнего известного расположения

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

Примечание.

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

В следующем примере кода демонстрируется проверка для кэшированного расположения:

public async Task<string> GetCachedLocation()
{
    try
    {
        Location location = await Geolocation.Default.GetLastKnownLocationAsync();

        if (location != null)
            return $"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
    }

    return "None";
}

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

Получение текущего расположения

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

Примечание.

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

В следующем примере кода показано, как запросить расположение устройства, поддерживая отмену:

private CancellationTokenSource _cancelTokenSource;
private bool _isCheckingLocation;

public async Task GetCurrentLocation()
{
    try
    {
        _isCheckingLocation = true;

        GeolocationRequest request = new GeolocationRequest(GeolocationAccuracy.Medium, TimeSpan.FromSeconds(10));

        _cancelTokenSource = new CancellationTokenSource();

        Location location = await Geolocation.Default.GetLocationAsync(request, _cancelTokenSource.Token);

        if (location != null)
            Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude: {location.Altitude}");
    }
    // Catch one of the following exceptions:
    //   FeatureNotSupportedException
    //   FeatureNotEnabledException
    //   PermissionException
    catch (Exception ex)
    {
        // Unable to get location
    }
    finally
    {
        _isCheckingLocation = false;
    }
}

public void CancelRequest()
{
    if (_isCheckingLocation && _cancelTokenSource != null && _cancelTokenSource.IsCancellationRequested == false)
        _cancelTokenSource.Cancel();
}

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

Предупреждение

GetLocationAsync может возвращаться null в некоторых сценариях. Это означает, что базовая платформа не может получить текущее расположение.

Прослушивание изменений расположения

Помимо запроса устройства к текущему расположению, вы можете прослушивать изменения расположения, пока приложение находится на переднем плане.

Чтобы проверка узнать, прослушивает ли приложение изменения расположения, есть IsListeningForeground свойство, которое можно запросить. После того как вы будете готовы начать прослушивание изменений расположения, следует вызвать StartListeningForegroundAsync метод. Этот метод начинает прослушивать обновления расположения и вызывает LocationChanged событие при изменении расположения, если приложение находится на переднем плане. Объект GeolocationLocationChangedEventArgs , сопровождающий это событие, имеет Location свойство типа Location, представляющее новое расположение, которое было обнаружено.

Примечание.

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

В следующем примере кода показано, как прослушивать изменение расположения и как обработать измененное расположение:

async void OnStartListening()
{
    try
    {
        Geolocation.LocationChanged += Geolocation_LocationChanged;
        var request = new GeolocationListeningRequest((GeolocationAccuracy)Accuracy);
        var success = await Geolocation.StartListeningForegroundAsync(request);

        string status = success
            ? "Started listening for foreground location updates"
            : "Couldn't start listening";
    }
    catch (Exception ex)
    {
        // Unable to start listening for location changes
    }
}

void Geolocation_LocationChanged(object sender, GeolocationLocationChangedEventArgs e)
{
    // Process e.Location to get the new location
}

Обработка ошибок может быть реализована путем регистрации обработчика событий для ListeningFailed события. Объект GeolocationListeningFailedEventArgs , сопровождающий это событие, имеет Error свойство типа GeolocationError, указывающее, почему прослушивание завершилось сбоем. ListeningFailed Когда событие возникает, прослушивание дальнейших изменений расположения останавливается и дальнейшие LocationChanged события не возникают.

Чтобы прекратить прослушивание изменений расположения, вызовите StopListeningForeground метод:

void OnStopListening()
{
    try
    {
        Geolocation.LocationChanged -= Geolocation_LocationChanged;
        Geolocation.StopListeningForeground();
        string status = "Stopped listening for foreground location updates";
    }
    catch (Exception ex)
    {
        // Unable to stop listening for location changes
    }
}

Примечание.

Метод StopListeningForeground не влияет, если приложение не прослушивает изменения расположения.

Правильность

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

Важно!

IOS имеет некоторые ограничения в отношении точности. Дополнительные сведения см. в разделе "Различия платформы".

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

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

Низкая

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

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

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

Высокая

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

Лучшее

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

Обнаружение макетных расположений

Некоторые устройства могут возвращать расположение макетов от поставщика или приложения, которое предоставляет расположения макетов. Это можно обнаружить с помощью IsFromMockProvider любого Location:

public async Task CheckMock()
{
    GeolocationRequest request = new GeolocationRequest(GeolocationAccuracy.Medium);
    Location location = await Geolocation.Default.GetLocationAsync(request);

    if (location != null && location.IsFromMockProvider)
    {
        // location is from a mock provider
    }
}

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

Метод 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(Double, Double, Double) принимает аргументы широты и долготы соответственно. Положительные значения широты находятся к северу от экватора, а положительные значения долготы — к востоку от нулевого меридиана. Используйте последний аргумент CalculateDistance, чтобы указать единицы измерения: мили или километры. Класс UnitConverters также определяет методы KilometersToMiles и MilesToKilometers для преобразования между двумя единицами измерения.

Различия между платформами

В этом разделе описываются различия платформы с API геолокации.

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

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

Свойство Location.ReducedAccuracy используется только iOS и возвращается false на всех других платформах.