Xamarin.Essentials: Geolocalização

A classe Geolocation fornece APIs para recuperar as coordenadas atuais de geolocalização do dispositivo.

Introdução

Para começar a usar essa API, leia o guia de introdução para Xamarin.Essentials garantir que a biblioteca esteja instalada e configurada corretamente em seus projetos.

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

As permissões Coarse Location e Fine Location são necessárias e devem ser configuradas no projeto do 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:

Abra o arquivo AssemblyInfo.cs na pasta Propriedades e adicione:

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

Ou atualize o manifesto do Android:

Abra o arquivo AndroidManifest.xml na pasta Propriedades e adicione o seguinte dentro do nó do manifesto:

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

Ou clique com o botão direito no projeto do Android e abra as propriedades do projeto. Em Manifesto do Android, localize a área Permissões necessárias: e marque as permissões ACCESS_COARSE_LOCATION e ACCESS_FINE_LOCATION. Isso atualizará automaticamente o arquivo AndroidManifest.xml.

Se seu aplicativo estiver visando o Android 10 - Q (API Nível 29 ou superior) e estiver solicitando LocationAlways, você também deverá adicionar a seguinte permissão ao AssemblyInfo.cs:

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

Ou diretamente no seu AndroidManifest.xml:

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

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

Essa API usa permissões de tempo de execução no Android. Certifique-se de que está totalmente inicializado e que o tratamento de Xamarin.Essentials permissões está configurado em seu aplicativo.

No projeto MainLauncher Android ou qualquer um Activity que é iniciado Xamarin.Essentials deve ser inicializado no OnCreate método:

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

Para lidar com permissões de tempo de execução no Android, Xamarin.Essentials deve receber qualquer OnRequestPermissionsResultarquivo . Adicione o seguinte código a todas as classes 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);
}

Usar a geolocalização

Adicione uma referência à Xamarin.Essentials sua classe:

using Xamarin.Essentials;

A API de Geolocalização também solicitará ao usuário permissões quando for necessário.

Você pode obter o último local conhecido do dispositivo chamando o método GetLastKnownLocationAsync. Isso geralmente é mais rápido do que fazer uma consulta completa, mas pode ser menos precisa e pode retornar null se não houver nenhum local armazenado em cache.

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
}

Para consultar as coordenadas do local atual do dispositivo, use GetLocationAsync. É melhor passar um GeolocationRequest e CancellationToken completo, pois pode demorar um pouco para obter o local do dispositivo.

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

Observe que todos os valores podem estar disponíveis devido à forma como cada dispositivo consulta a geolocalização por meio de provedores diferentes. Por exemplo, a propriedade pode ser null, ter um valor de 0, ou ter um valor positivo, que está em metros acima do Altitude nível do mar. Outros valores que podem não estar presentes incluem Speed e Course.

Precisão da geolocalização

A tabela a seguir descreve a precisão por plataforma:

O menor

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

Baixo

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

Médio (padrão)

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

Alto

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

Melhor

Plataforma Distância (em metros)
Android 0–100
iOS ~0
UWP <= 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.

var request = new GeolocationRequest(GeolocationAccuracy.Medium);
var location = await Geolocation.GetLocationAsync(request);

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

Distância entre dois locais

As classes Location e LocationExtensions definem métodos CalculateDistance que permitem o cálculo da distância entre duas localizações geográficas. Essa distância calculada não considera estradas ou outros caminhos e é simplesmente a distância mais curta entre os dois pontos ao longo da superfície da Terra, também conhecido como ortodromia ou, coloquialmente, a distância "em linha reta".

Aqui está um exemplo:

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 tem argumentos de latitude e longitude, nessa ordem. 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 entre plataformas

A altitude é calculada de forma diferente em cada plataforma.

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

API

Encontre mais vídeos sobre o Xamarin no Channel 9 e no YouTube.