Geolokalizacja

Przeglądaj przykład. Przeglądanie przykładu

W tym artykule opisano sposób używania interfejsu użytkownika aplikacji wieloplatformowej platformy .NET (.NET MAUI). IGeolocation Ten interfejs udostępnia interfejsy API umożliwiające pobieranie bieżących współrzędnych geolokalizacji urządzenia.

Domyślna implementacja interfejsu IGeolocation jest dostępna za pośrednictwem właściwości Geolocation.Default. Zarówno interfejs IGeolocation, jak i klasa Geolocation znajdują się w przestrzeni nazw Microsoft.Maui.Devices.Sensors.

Wprowadzenie

Aby uzyskać dostęp do funkcji geolokalizacji , wymagana jest następująca konfiguracja specyficzna dla platformy:

Należy określić uprawnienia do ogólnej lub dokładnej lokalizacji, lub oba, i skonfigurować je w projekcie systemu Android.

Ponadto jeśli aplikacja jest przeznaczona dla systemu Android 5.0 (poziom 21 interfejsu API) lub nowszy, musisz zadeklarować, że aplikacja korzysta z funkcji sprzętowych w pliku manifestu. Można to dodać w następujący sposób:

  • Dodaj uprawnienie oparte na zestawie:

    Otwórz plik Platforms/Android/MainApplication.cs i dodaj następujące atrybuty asemblacji po using dyrektyw:

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

    Jeśli aplikacja jest przeznaczona dla systemu Android 10 — Q (poziom interfejsu API 29 lub nowszy) i żąda LocationAlways, musisz również dodać to żądanie uprawnień:

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

    - lub -

  • Zaktualizuj manifest systemu Android:

    Otwórz plik Platforms/Android/AndroidManifest.xml i dodaj następujący kod w węźle 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" />
    

    Jeśli aplikacja jest przeznaczona dla systemu Android 10 — Q (poziom interfejsu API 29 lub nowszy) i żąda LocationAlways, musisz również dodać to żądanie uprawnień:

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

    - lub -

  • Zaktualizuj manifest systemu Android w edytorze manifestu:

    W programie Visual Studio kliknij dwukrotnie plik Platforms/Android/AndroidManifest.xml, aby otworzyć edytor manifestu systemu Android. Następnie w obszarze Wymagane uprawnienia sprawdź uprawnienia wymienione powyżej. Spowoduje to automatyczne zaktualizowanie pliku AndroidManifest.xml.

Tip

Zapoznaj się z dokumentacją systemu Android dotyczącą aktualizacji lokalizacji w tle, ponieważ należy wziąć pod uwagę wiele ograniczeń.

Uzyskaj ostatnią znaną lokalizację

Urządzenie mogło zbuforować najnowszą lokalizację urządzenia. GetLastKnownLocationAsync() Użyj metody , aby uzyskać dostęp do buforowanej lokalizacji, jeśli jest dostępna. Jest to często szybsze niż wykonywanie pełnego zapytania o lokalizację, ale może być mniej dokładne. Jeśli nie istnieje lokalizacja buforowana, ta metoda zwraca wartość null.

Note

W razie potrzeby interfejs API geolokalizacji prosi użytkownika o przyznanie uprawnień.

W poniższym przykładzie kodu pokazano sprawdzanie lokalizacji buforowanej:

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

W zależności od urządzenia nie wszystkie wartości lokalizacji mogą być dostępne. Na przykład właściwość Altitude może być null, mieć wartość 0 lub wartość dodatnią wskazującą metry nad poziomem morza. Inne wartości, które mogą nie być obecne, obejmują właściwość Speed oraz właściwość Course.

Pobieranie bieżącej lokalizacji

Sprawdzanie ostatniej znanej lokalizacji urządzenia może być szybsze, ale może być niedokładne. Użyj metody , GetLocationAsync aby wysłać zapytanie do urządzenia dla bieżącej lokalizacji. Można skonfigurować dokładność i limit czasu zapytania. Najlepszym rozwiązaniem jest przeciążenie metody korzystającej z GeolocationRequest parametrów i CancellationToken , ponieważ uzyskanie lokalizacji urządzenia może zająć trochę czasu.

Note

W razie potrzeby interfejs API geolokalizacji prosi użytkownika o przyznanie uprawnień.

W poniższym przykładzie kodu pokazano, jak zażądać lokalizacji urządzenia, zapewniając możliwość anulowania:

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

Nie wszystkie wartości lokalizacji mogą być dostępne w zależności od urządzenia. Na przykład właściwość Altitude może być null, mieć wartość 0 lub wartość dodatnią wskazującą metry nad poziomem morza. Inne wartości, które mogą nie być obecne, obejmują Speed i Course.

Warning

GetLocationAsync może zwrócić null w niektórych scenariuszach. Oznacza to, że platforma bazowa nie może uzyskać bieżącej lokalizacji.

Nasłuchiwanie zmian lokalizacji

Oprócz zapytania urządzenia o bieżącą lokalizację, można nasłuchiwać zmian lokalizacji, gdy aplikacja jest na pierwszym planie.

Aby sprawdzić, czy aplikacja obecnie nasłuchuje zmian lokalizacji, można zapytać o właściwość IsListeningForeground. Dokładność wykrywania zmian lokalizacji można kontrolować, przekazując do konstruktora GeolocationAccuracy jedną z wartości wyliczenia GeolocationListeningRequest. Gdy wszystko będzie gotowe do rozpoczęcia nasłuchiwania zmian lokalizacji, należy wywołać metodę StartListeningForegroundAsync . Ta metoda rozpoczyna nasłuchiwanie aktualizacji lokalizacji i zgłasza LocationChanged zdarzenie, gdy lokalizacja ulegnie zmianie, pod warunkiem, że aplikacja jest na pierwszym planie. Obiekt GeolocationLocationChangedEventArgs , który towarzyszy temu zdarzeniu, ma Location właściwość typu Location, która reprezentuje wykrytą nową lokalizację.

Note

W razie potrzeby interfejs API geolokalizacji prosi użytkownika o przyznanie uprawnień.

W poniższym przykładzie kodu pokazano, jak nasłuchiwać zmiany lokalizacji i jak przetwarzać zmienioną lokalizację:

async void OnStartListening()
{
    try
    {
        Geolocation.LocationChanged += Geolocation_LocationChanged;
        // Using GeolocationAccuracy.Medium as a balance between accuracy and power consumption.
        // Developers can adjust this value to High or Low based on their specific requirements.
        var request = new GeolocationListeningRequest(GeolocationAccuracy.Medium);
        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
}

W platformie .NET 11 właściwość MinimumDistance w elemencie Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest określa minimalną odległość w metrach między aktualizacjami lokalizacji na pierwszym planie. Połącz je z GeolocationListeningRequest.MinimumTime , aby ograniczyć aktualizacje zarówno o czas, jak i odległość. Wartość 0 wyłącza filtr odległości:

var request = new GeolocationListeningRequest(GeolocationAccuracy.Medium)
{
    MinimumTime = TimeSpan.FromSeconds(10),
    MinimumDistance = 25
};

var success = await Geolocation.StartListeningForegroundAsync(request);

StartListeningForegroundAsync sprawdza, czy MinimumTime wartość jest większa niż lub równa TimeSpan.Zero i jest MinimumDistance większa lub równa 0. Android przekazuje MinimumDistance do LocationManager.RequestLocationUpdates, systemy iOS i Mac Catalyst ustawiają CLLocationManager.DistanceFilter, a system Windows ustawia Geolocator.MovementThreshold.

Obsługę błędów można zaimplementować, rejestrując program obsługi zdarzeń dla ListeningFailed zdarzenia. Obiekt GeolocationListeningFailedEventArgs , który towarzyszy temu zdarzeniu, ma Error właściwość typu GeolocationError, która wskazuje, dlaczego nasłuchiwanie nie powiodło się. Po podniesieniu zdarzenia ListeningFailed zatrzymuje się nasłuchiwanie dalszych zmian lokalizacji i nie są wywoływane żadne dalsze zdarzenia LocationChanged.

Aby zatrzymać nasłuchiwanie zmian lokalizacji, wywołaj metodę 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
    }
}

Note

Metoda StopListeningForeground nie ma wpływu, gdy aplikacja nie nasłuchuje zmian lokalizacji.

Sprawdzanie, czy usługi lokalizacji są włączone

Klasa Geolocation ma właściwość tylko IsEnabled do odczytu, która może służyć do określenia, czy usługi lokalizacji zostały włączone na urządzeniu.

Accuracy

W poniższych sekcjach przedstawiono dokładność lokalizacji w zależności od platformy.

Important

System iOS ma pewne ograniczenia dotyczące dokładności. Aby uzyskać więcej informacji, zobacz sekcję Różnice między platformami .

Lowest

Platform Odległość (w metrach)
Android 500
iOS 3000
Windows 1000 - 5000

Low

Platform Odległość (w metrach)
Android 500
iOS 1000
Windows 300 - 3000

Średni (wartość domyślna)

Platform Odległość (w metrach)
Android 100 - 500
iOS 100
Windows 30-500

High

Platform Odległość (w metrach)
Android 0 - 100
iOS 10
Windows <= 10

Best

Platform Odległość (w metrach)
Android 0 - 100
iOS ~0
Windows <= 10

Wykrywanie pozornych lokalizacji

Niektóre urządzenia mogą zwracać fikcyjną lokalizację od dostawcy lub przez aplikację udostępniającą fikcyjne lokalizacje. Możesz to wykryć, używając elementu IsFromMockProvider w dowolnym 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
    }
}

Odległość między dwiema lokalizacjami

Metoda CalculateDistance oblicza odległość między dwiema lokalizacjami geograficznymi. Ta obliczona odległość nie bierze pod uwagę dróg ani innych ścieżek i jest tylko najkrótszą odległością między dwoma punktami na powierzchni Ziemi. To obliczenie jest określane jako obliczanie odległości z dużym okręgiem .

Poniższy kod oblicza odległość między miastami Stanów Zjednoczonych Ameryki Boston i San Francisco:

Location boston = new Location(42.358056, -71.063611);
Location sanFrancisco = new Location(37.783333, -122.416667);

double miles = Location.CalculateDistance(boston, sanFrancisco, DistanceUnits.Miles);

Konstruktor Location(Double, Double, Double) akceptuje odpowiednio argumenty szerokości geograficznej i długości geograficznej. Dodatnie wartości szerokości geograficznej są na północ od równika, a dodatnie wartości długości geograficznej są na wschód od Regionu Głównego. Użyj argumentu końcowego, aby w CalculateDistance określić mile lub kilometry. Klasa UnitConverters definiuje również metody KilometersToMiles oraz MilesToKilometers do konwertowania między dwiema jednostkami.

Różnice między platformami

W tej części opisano różnice specyficzne dla platformy związane z interfejsem API geolokalizacji.

Wysokość jest obliczana inaczej na każdej platformie.

W systemie Android wysokość, jeśli jest dostępna, jest zwracana w metrach powyżej wielokropka WGS 84 odwołania. Jeśli ta lokalizacja nie ma wysokości, 0.0 zostanie zwrócona.

Note

Niektóre urządzenia z systemem Android bez czujnika barometrycznego zwracają 0.0 dla Altitude, gdy nie są dostępne dane dotyczące wysokości. Jest to nie do odróżnienia od rzeczywistego podniesienia poziomu morza. Traktuj 0.0 jako nieznaną wartość, a nie poziom morza, a następnie zweryfikuj location.Altitude != 0 przed użyciem danych wysokości w aplikacji.

W systemie Android 14 (API 34) i nowszych wersjach platforma .NET MAUI używa wysokości względem średniego poziomu morza, gdy jest ona dostępna. W tym przypadku Altitude jest zwracany w metrach powyżej geoidu i Location.AltitudeReferenceSystem ma wartość AltitudeReferenceSystem.Geoid.

Gdy wysokość nad średnim poziomem morza nie jest dostępna, Android używa wartości altitude wyrażonej w metrach powyżej elipsoidy odniesienia WGS 84, a AltitudeReferenceSystem to AltitudeReferenceSystem.Ellipsoid. Jeśli nie ma dostępnej wysokości, Altitude jest null i AltitudeReferenceSystem ma wartość AltitudeReferenceSystem.Unspecified.

Właściwość Location.ReducedAccuracy jest używana tylko przez system iOS i zwraca wartość false na wszystkich innych platformach.