Partilhar via


Geolocalização

Browse sample. Procurar no exemplo

Este artigo descreve como você pode usar a interface do usuário do aplicativo .NET multiplataforma (.NET MAUI) IGeolocation. Esta interface fornece APIs para recuperar as coordenadas de localização geográfica atuais do dispositivo.

A implementação padrão da interface IGeolocation está disponível por meio da propriedade Geolocation.Default. A interface IGeolocation e a classe Geolocation estão contidas no namespace Microsoft.Maui.Devices.Sensors.

Introdução

Para acessar a funcionalidade de Geolocalização, a seguinte configuração específica da plataforma é necessária:

Permissões de localização de alta ou baixa granularidade, ou ambas, devem ser especificadas e devem ser configuradas no projeto Android.

Além disso, se o seu aplicativo for destinado ao Android 5.0 (API nível 21) ou superior, você deverá declarar que ele usa os recursos de hardware no arquivo de manifesto. Isso pode ser usado das seguintes maneiras:

  • Adicione a permissão baseada em assembly:

    Abra o arquivo Platforms/Android/MainApplication.cs e adicione os seguintes atributos de assembly após as diretivas 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)]
    

    Se o seu aplicativo estiver direcionando o Android 10 – Q (Nível de API 29 ou superior) e estiver solicitando LocationAlways, você também deverá adicionar esta solicitação de permissão:

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

    - ou -

  • Atualize o manifesto do Android:

    Abra o arquivo Platforms/Android/AndroidManifest.xml e adicione o seguinte no nó 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" />
    

    Se o seu aplicativo estiver direcionando o Android 10 – Q (Nível de API 29 ou superior) e estiver solicitando LocationAlways, você também deverá adicionar esta solicitação de permissão:

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

    - ou -

  • Atualize o Manifesto do Android no editor de manifesto:

    No Visual Studio, clique duas vezes no arquivo Platforms/Android/AndroidManifest.xml para abrir o editor de manifesto do Android. Em seguida, em Permissões necessárias, verifique as permissões listadas acima. Isso atualizará automaticamente o arquivo AndroidManifest.xml.

Dica

Certifique-se de ler a documentação do Android sobre atualizações de localização em segundo plano, pois há muitas restrições que precisam ser consideradas.

Obter o último local conhecido

O dispositivo pode ter armazenado em cache o local mais recente do dispositivo. Use o método GetLastKnownLocationAsync() para acessar o local armazenado em cache, se disponível. Isso geralmente é mais rápido do que fazer uma consulta de localização completa, mas pode ser menos preciso. Se nenhum local armazenado em cache existir, este método retornará null.

Observação

Quando necessário, a API de Geolocalização solicita permissões ao usuário.

O exemplo de código a seguir demonstra a verificação de um local armazenado em cache:

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

Dependendo do dispositivo, nem todos os valores de localização podem estar disponíveis. Por exemplo, a propriedade Altitude pode ser null, ter um valor de 0 ou ter um valor positivo indicando os metros acima do nível do mar. Outros valores que podem não estar presentes incluem as propriedades Speed e Course.

Obter o local atual

Embora a verificação do último local conhecido do dispositivo possa ser mais rápida, ela pode ser imprecisa. Use o método GetLocationAsync para consultar o dispositivo para o local atual. Você pode configurar a precisão e o tempo limite da consulta. É melhor para a sobrecarga de método que usa os parâmetros GeolocationRequest e CancellationToken, pois pode levar algum tempo para obter a localização do dispositivo.

Observação

Quando necessário, a API de Geolocalização solicita permissões ao usuário.

O exemplo de código a seguir demonstra como solicitar a localização do dispositivo e dar suporte ao cancelamento:

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

Nem todos os valores de localização podem estar disponíveis, dependendo do dispositivo. Por exemplo, a propriedade Altitude pode ser null, ter um valor de 0 ou ter um valor positivo indicando os metros acima do nível do mar. Outros valores que podem não estar presentes incluem Speed e Course.

Aviso

GetLocationAsync pode retornar null em alguns cenários. Isso indica que a plataforma subjacente não consegue obter o local atual.

Ouvir as alterações de localização

Além de consultar o dispositivo para o local atual, você pode escutar as alterações de localização enquanto um aplicativo está em primeiro plano.

Para verificar se o aplicativo está escutando alterações de localização no momento, há uma propriedade IsListeningForeground que você pode consultar. Quando estiver pronto para começar a escutar as alterações de localização, você deverá chamar o método StartListeningForegroundAsync. Este método começa a escutar atualizações de localização e gera o evento LocationChanged quando o local é alterado, desde que o aplicativo esteja em primeiro plano. O objeto GeolocationLocationChangedEventArgs que acompanha esse evento tem uma propriedade Location, de tipo Location, que representa o novo local que foi detectado.

Observação

Quando necessário, a API de Geolocalização solicita permissões ao usuário.

O exemplo de código a seguir demonstra como escutar uma alteração de local e como processar o local alterado:

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
}

O tratamento de erros pode ser implementado registrando um manipulador de eventos para o evento ListeningFailed. O objeto GeolocationListeningFailedEventArgs que acompanha esse evento tem uma propriedade Error, de tipo GeolocationError, que indica por que a escuta falhou. Quando o evento ListeningFailed é acionado, a escuta de novas alterações de local é interrompida e nenhum evento LocationChanged adicional é gerado.

Para parar de escutar as alterações de localização, chame o método 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
    }
}

Observação

O método StopListeningForeground não tem efeito quando o aplicativo não está escutando alterações de localização.

Precisão

As seções a seguir descrevem a distância de precisão do local, por plataforma:

Importante

O iOS tem algumas limitações em relação à precisão. Para obter mais informações, confira a seção Diferenças entre plataformas.

O menor

Plataforma Distância (em metros)
Android 500
iOS 3000
Windows 1.000–5.000

Baixo

Plataforma Distância (em metros)
Android 500
iOS 1000
Windows 300–3.000

Médio (padrão)

Plataforma Distância (em metros)
Android 100–500
iOS 100
Windows 30–500

Alto

Plataforma Distância (em metros)
Android 0–100
iOS 10
Windows <= 10

Melhor

Plataforma Distância (em metros)
Android 0–100
iOS ~0
Windows <= 10

Detectando locais fictícios

Alguns dispositivos podem retornar um local fictício do provedor ou por um aplicativo que fornece locais fictícios. Você pode detectar isso usando o IsFromMockProvider em qualquer 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
    }
}

Distância entre dois locais

O método CalculateDistance calcula a distância entre duas localizações geográficas. Essa distância calculada não leva em conta estradas ou outros caminhos, e é apenas a distância mais curta entre os dois pontos ao longo da superfície da Terra. Esse cálculo é conhecido como o cálculo de ortodromia (great-circle distance).

O código a seguir calcula a distância entre as cidades de Boston e São Francisco, nos Estados Unidos da América:

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

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

O construtor Location(Double, Double, Double) aceita os argumentos de latitude e longitude, respectivamente. Os valores de latitude positiva estão ao norte do Equador, e os valores de longitude positiva estão a leste do Meridiano primário. Use o argumento final para CalculateDistance a fim de especificar milhas ou quilômetros. A classe UnitConverters também define os métodos KilometersToMiles e MilesToKilometers para conversão entre as duas unidades.

Diferenças de plataforma

Esta seção descreve as diferenças específicas entre plataformas com a API de geolocalização.

A altitude é calculada de forma diferente em cada plataforma.

No Android, a altitude, se disponível, é retornada em metros acima do elipsóide de referência do WGS 84. Se esse local não tiver uma altitude, 0.0 será retornado.

A propriedade Location.ReducedAccuracy é usada apenas pelo iOS e retorna false em todas as outras plataformas.