Compartilhar via


Serviços de localização no Android

Este guia apresenta o reconhecimento de localização em aplicativos Android e ilustra como obter a localização do usuário usando a API do Serviço de Localização do Android, bem como o provedor de localização fundido disponível com a API dos Serviços de Localização do Google.

O Android fornece acesso a várias tecnologias de localização, como localização de torre de celular, Wi-Fi e GPS. Os detalhes de cada tecnologia de localização são abstraídos por meio de provedores de localização, permitindo que os aplicativos obtenham locais da mesma maneira, independentemente do provedor usado. Este guia apresenta o provedor de localização fundida, uma parte do Google Play Services, que determina de forma inteligente a melhor maneira de obter a localização dos dispositivos com base em quais provedores estão disponíveis e como o dispositivo está sendo usado. API do Serviço de Localização do Android e mostra como se comunicar com o Serviço de Localização do Sistema usando um LocationManagerarquivo . A segunda parte do guia explora a API dos Serviços de Localização do Android usando o LocationManager.

Como regra geral, os aplicativos devem preferir usar o provedor de localização fundida, retornando a API de Serviço de Localização do Android mais antiga apenas quando necessário.

Fundamentos de localização

No Android, independentemente da API escolhida para trabalhar com dados de localização, vários conceitos permanecem os mesmos. Esta seção apresenta Provedores de Localização e permissões relacionadas à localização.

Provedores de localização

Diversas tecnologias são utilizadas internamente para identificar a localização do usuário. O hardware usado depende do tipo de provedor de localização selecionado para o trabalho de coleta de dados. O Android usa três provedores de localização:

  • GPS Provider - GPS dá a localização mais precisa, usa a maior potência, e funciona melhor ao ar livre. Este provedor usa uma combinação de GPS e GPS assistido (aGPS), que retorna dados de GPS coletados por torres de celular.

  • Provedor de rede – Fornece uma combinação de dados Wi-Fi e celular, incluindo dados aGPS coletados por torres de celular. Ele usa menos energia do que o provedor GPS, mas retorna dados de localização de precisão variável.

  • Provedor passivo – Uma opção de "piggyback" usando provedores solicitados por outros aplicativos ou serviços para gerar dados de localização em um aplicativo. Esta é uma opção menos confiável, mas que economiza energia, ideal para aplicativos que não exigem atualizações constantes de localização para funcionar.

Os provedores de localização nem sempre estão disponíveis. Por exemplo, podemos querer usar o GPS para nosso aplicativo, mas o GPS pode estar desativado em Configurações ou o dispositivo pode não ter GPS. Se um provedor específico não estiver disponível, a escolha desse provedor poderá retornar null.

Permissões de localização

Um aplicativo com reconhecimento de localização precisa acessar os sensores de hardware de um dispositivo para receber dados de GPS, Wi-Fi e celular. O acesso é controlado por meio de permissões apropriadas no Manifesto Android do aplicativo. Há duas permissões disponíveis – dependendo dos requisitos do seu aplicativo e da sua escolha de API, você desejará permitir uma:

  • ACCESS_FINE_LOCATION – Permite o acesso de um aplicativo ao GPS. Necessário para as opções Provedor GPS e Provedor Passivo (Provedor Passivo precisa de permissão para acessar dados GPS coletados por outro aplicativo ou Serviço). Permissão opcional para o Provedor de Rede.

  • ACCESS_COARSE_LOCATION – Permite o acesso de um aplicativo à localização de celular e Wi-Fi. Necessário para o Provedor de Rede se ACCESS_FINE_LOCATION não estiver definido.

Para aplicativos destinados à API versão 21 (Android 5.0 Lollipop) ou superior, você pode habilitar ACCESS_FINE_LOCATION e ainda executar em dispositivos que não têm hardware GPS. Se seu aplicativo exigir hardware GPS, você deverá adicionar explicitamente um android.hardware.location.gpsuses-feature elemento ao Manifesto do Android. Para obter mais informações, consulte a referência do elemento de recurso de uso do Android.

Para definir as permissões, expanda a pasta Propriedades no Painel de Soluções e clique duas vezes em AndroidManifest.xml. As permissões serão listadas em Permissões necessárias:

Captura de tela das configurações de Permissões Necessárias do Manifesto do Android

A configuração de qualquer uma dessas permissões informa ao Android que seu aplicativo precisa de permissão do usuário para acessar os provedores de localização. Os dispositivos que executam o nível de API 22 (Android 5.1) ou inferior solicitarão que o usuário conceda essas permissões sempre que o aplicativo for instalado. Em dispositivos que executam o nível de API 23 (Android 6.0) ou superior, o aplicativo deve executar uma verificação de permissão de tempo de execução antes de fazer uma solicitação ao provedor de localização.

Observação

Nota: A configuração ACCESS_FINE_LOCATION implica o acesso a dados de localização grosseiros e finos. Você nunca deve ter que definir ambas as permissões, apenas a permissão mínima que seu aplicativo requer para funcionar.

Este trecho é um exemplo de como verificar se um aplicativo tem permissão para a ACCESS_FINE_LOCATION permissão:

 if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.AccessFineLocation) == Permission.Granted)
{
    StartRequestingLocationUpdates();
    isRequestingLocationUpdates = true;
}
else
{
    // The app does not have permission ACCESS_FINE_LOCATION 
}

Os aplicativos devem ser tolerantes com o cenário em que o usuário não concederá permissão (ou revogou a permissão) e ter uma maneira de lidar normalmente com essa situação. Consulte o Guia de permissões para obter mais detalhes sobre como implementar verificações de permissão em tempo de execução no Xamarin.Android.

Usando o provedor de localização fundida

O provedor de localização fundido é a maneira preferida para os aplicativos Android receberem atualizações de localização do dispositivo, pois selecionará eficientemente o provedor de localização durante o tempo de execução para fornecer as melhores informações de localização de forma eficiente em termos de bateria. Por exemplo, um usuário andando ao ar livre obtém a melhor leitura de localização com GPS. Se o usuário andar dentro de casa, onde o GPS funciona mal (se é que funciona), o provedor de localização fundida pode mudar automaticamente para Wi-Fi, que funciona melhor em ambientes fechados.

A API do provedor de localização fundida fornece uma variedade de outras ferramentas para capacitar aplicativos com reconhecimento de localização, incluindo cerca geográfica e monitoramento de atividades. Nesta seção, vamos nos concentrar nos conceitos básicos de configuração do LocationClient, estabelecer provedores e obter a localização do usuário.

O provedor de localização fundida faz parte do Google Play Services. O pacote do Google Play Services deve ser instalado e configurado corretamente no aplicativo para que a API do provedor de localização fundida funcione, e o dispositivo deve ter o APK do Google Play Services instalado.

Antes que um aplicativo Xamarin.Android possa usar o provedor de localização fundida, ele deve adicionar o pacote Xamarin.GooglePlayServices.Location ao projeto. Além disso, as instruções a seguir using devem ser adicionadas a quaisquer arquivos de origem que façam referência às classes descritas abaixo:

using Android.Gms.Common;
using Android.Gms.Location;

Verificar se o Google Play Services está instalado

Um Xamarin.Android falhará se tentar usar o provedor de localização fundido quando o Google Play Services não estiver instalado (ou desatualizado), ocorrerá uma exceção de tempo de execução. Se o Google Play Services não estiver instalado, o aplicativo deverá retornar ao Serviço de localização do Android discutido acima. Se o Google Play Services estiver desatualizado, o aplicativo poderá exibir uma mensagem ao usuário solicitando que ele atualize a versão instalada do Google Play Services.

Este trecho é um exemplo de como uma atividade do Android pode verificar programaticamente se o Google Play Services está instalado:

bool IsGooglePlayServicesInstalled()
{
    var queryResult = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(this);
    if (queryResult == ConnectionResult.Success)
    {
        Log.Info("MainActivity", "Google Play Services is installed on this device.");
        return true;
    }

    if (GoogleApiAvailability.Instance.IsUserResolvableError(queryResult))
    {
        // Check if there is a way the user can resolve the issue
        var errorString = GoogleApiAvailability.Instance.GetErrorString(queryResult);
        Log.Error("MainActivity", "There is a problem with Google Play Services on this device: {0} - {1}",
                  queryResult, errorString);

        // Alternately, display the error to the user.
    }

    return false;
}

FusedLocationProviderClient

Para interagir com o provedor de localização fundida, um aplicativo Xamarin.Android deve ter uma instância do FusedLocationProviderClient. Essa classe expõe os métodos necessários para assinar atualizações de local e recuperar o último local conhecido do dispositivo.

O OnCreate método de uma Atividade é um local adequado para obter uma referência ao FusedLocationProviderClient, conforme demonstrado no seguinte trecho de código:

public class MainActivity: AppCompatActivity
{
    FusedLocationProviderClient fusedLocationProviderClient;

    protected override void OnCreate(Bundle bundle) 
    {
        fusedLocationProviderClient = LocationServices.GetFusedLocationProviderClient(this);
    }
}

Obtendo o último local conhecido

O FusedLocationProviderClient.GetLastLocationAsync() método fornece uma maneira simples e sem bloqueio para um aplicativo Xamarin.Android obter rapidamente a última localização conhecida do dispositivo com sobrecarga de codificação mínima.

Este trecho mostra como usar o GetLastLocationAsync método para recuperar o local do dispositivo:

async Task GetLastLocationFromDevice()
{
    // This method assumes that the necessary run-time permission checks have succeeded.
    getLastLocationButton.SetText(Resource.String.getting_last_location);
    Android.Locations.Location location = await fusedLocationProviderClient.GetLastLocationAsync();

    if (location == null)
    {
        // Seldom happens, but should code that handles this scenario
    }
    else
    {
        // Do something with the location 
        Log.Debug("Sample", "The latitude is " + location.Latitude);
    }
}

Subscrever atualizações de localização

Um aplicativo Xamarin.Android também pode assinar atualizações de localização do provedor de localização fundido usando o FusedLocationProviderClient.RequestLocationUpdatesAsync método, conforme mostrado neste trecho de código:

await fusedLocationProviderClient.RequestLocationUpdatesAsync(locationRequest, locationCallback);

Esse método usa dois parâmetros:

  • Android.Gms.Location.LocationRequest – Um LocationRequest objeto é como um aplicativo Xamarin.Android passa os parâmetros sobre como o provedor de localização fundido deve funcionar. As LocationRequest informações de retenção, como a frequência com que as solicitações devem ser feitas ou a importância de uma atualização de localização precisa. Por exemplo, uma solicitação de localização importante fará com que o dispositivo use o GPS e, consequentemente, mais energia ao determinar a localização. Este trecho de código mostra como criar um LocationRequest para um local com alta precisão, verificando aproximadamente a cada cinco minutos uma atualização de local (mas não antes de dois minutos entre as solicitações). O provedor de localização fundida usará um LocationRequest como orientação para qual provedor de local usar ao tentar determinar a localização do dispositivo:

    LocationRequest locationRequest = new LocationRequest()
                                      .SetPriority(LocationRequest.PriorityHighAccuracy)
                                      .SetInterval(60 * 1000 * 5)
                                      .SetFastestInterval(60 * 1000 * 2);
    
  • Android.Gms.Location.LocationCallback – Para receber atualizações de localização, um aplicativo Xamarin.Android deve subclassificar a LocationProvider classe abstrata. Essa classe expôs dois métodos que podem ser invocados pelo provedor de localização fundido para atualizar o aplicativo com informações de localização. Isso será discutido com mais detalhes a seguir.

Para notificar um aplicativo Xamarin.Android de uma atualização de local, o provedor de localização fundido invocará o LocationCallBack.OnLocationResult(LocationResult result). O Android.Gms.Location.LocationResult parâmetro conterá as informações de local de atualização.

Quando o provedor de localização fundida detecta uma alteração na disponibilidade dos dados de localização, ele chamará o LocationProvider.OnLocationAvailability(LocationAvailability locationAvailability) método. Se a LocationAvailability.IsLocationAvailable propriedade retornar true, pode-se presumir que os resultados de localização do dispositivo relatados por OnLocationResult são tão precisos e atualizados quanto exigido pelo LocationRequest. Se IsLocationAvailable for false, nenhum resultado de localização será retornado por OnLocationResult.

Este trecho de código é uma implementação de exemplo do LocationCallback objeto:

public class FusedLocationProviderCallback : LocationCallback
{
    readonly MainActivity activity;

    public FusedLocationProviderCallback(MainActivity activity)
    {
        this.activity = activity;
    }

    public override void OnLocationAvailability(LocationAvailability locationAvailability)
    {
        Log.Debug("FusedLocationProviderSample", "IsLocationAvailable: {0}",locationAvailability.IsLocationAvailable);
    }

    public override void OnLocationResult(LocationResult result)
    {
        if (result.Locations.Any())
        {
            var location = result.Locations.First();
            Log.Debug("Sample", "The latitude is :" + location.Latitude);
        }
        else
        {
            // No locations to work with.
        }
    }
}

Usando a API do Serviço de Localização do Android

O Serviço de Localização do Android é uma API mais antiga para usar informações de localização no Android. Os dados de localização são coletados por sensores de hardware e coletados por um serviço do sistema, que é acessado no aplicativo com uma LocationManager classe e um ILocationListenerarquivo .

O Serviço de localização é mais adequado para aplicativos que devem ser executados em dispositivos que não têm o Google Play Services instalado.

O Serviço de Localização é um tipo especial de Serviço gerenciado pelo Sistema. Um Serviço do Sistema interage com o hardware do dispositivo e está sempre em execução. Para acessar as atualizações de localização em nosso aplicativo, assinaremos as atualizações de localização do Serviço de Localização do sistema usando uma LocationManager e uma RequestLocationUpdates chamada.

Para obter a localização do usuário usando o Serviço de Localização do Android envolve várias etapas:

  1. Obtenha uma referência para o LocationManager serviço.
  2. Implemente a ILocationListener interface e manipule eventos quando o local for alterado.
  3. Use o para solicitar atualizações de LocationManager local para um provedor especificado. O ILocationListener da etapa anterior será usado para receber retornos de chamada do LocationManager.
  4. Pare as atualizações de local quando o aplicativo não for mais apropriado para receber atualizações.

Gerente de Localização

Podemos acessar o serviço de localização do sistema com uma instância da LocationManager classe. LocationManager é uma classe especial que nos permite interagir com o serviço de localização do sistema e chamar métodos nele. Um aplicativo pode obter uma referência ao LocationManager chamando GetSystemService e passando em um tipo de serviço, conforme mostrado abaixo:

LocationManager locationManager = (LocationManager) GetSystemService(Context.LocationService);

OnCreate é um bom lugar para obter uma referência para o LocationManager. É uma boa ideia manter o LocationManager como uma variável de classe, para que possamos chamá-lo em vários pontos do ciclo de vida da atividade.

Solicitar atualizações de localização do LocationManager

Uma vez que o aplicativo tem uma referência ao LocationManager, ele precisa dizer que LocationManager tipo de informações de localização que são necessárias e com que frequência essas informações devem ser atualizadas. Faça isso chamando RequestLocationUpdates o LocationManager objeto e passando alguns critérios para atualizações e um retorno de chamada que receberá as atualizações de local. Esse retorno de chamada é um tipo que deve implementar a ILocationListener interface (descrita com mais detalhes mais adiante neste guia).

O RequestLocationUpdates método informa ao Serviço de localização do sistema que seu aplicativo gostaria de começar a receber atualizações de local. Esse método permite que você especifique o provedor, bem como limites de tempo e distância para controlar a frequência de atualização. Por exemplo, o método abaixo solicita atualizações de localização do provedor de localização GPS a cada 2000 milissegundos e somente quando o local muda mais de 1 metro:

// For this example, this method is part of a class that implements ILocationListener, described below
locationManager.RequestLocationUpdates(LocationManager.GpsProvider, 2000, 1, this);

Um aplicativo deve solicitar atualizações de local somente com a frequência necessária para que o aplicativo tenha um bom desempenho. Isso preserva a vida útil da bateria e cria uma melhor experiência para o usuário.

Respondendo a atualizações do LocationManager

Depois que um aplicativo solicita atualizações do LocationManager, ele pode receber informações do Serviço implementando a ILocationListener interface. Essa interface fornece quatro métodos para escutar o Serviço de localização e o provedor de localização, OnLocationChanged. O Sistema chamará OnLocationChanged quando a localização do usuário for alterada o suficiente para se qualificar como uma alteração de local de acordo com os Critérios definidos ao solicitar atualizações de localização.

O código a ILocationListener seguir mostra os métodos na interface:

public class MainActivity : AppCompatActivity, ILocationListener
{
    TextView latitude;
    TextView longitude;
    
    public void OnLocationChanged (Location location)
    {
        // called when the location has been updated.
    }
    
    public OnProviderDisabled(string locationProvider)
    {
        // called when the user disables the provider
    }
    
    public OnProviderEnabled(string locationProvider)
    {
        // called when the user enables the provider
    }
    
    public OnStatusChanged(string locationProvider, Availability status, Bundle extras)
    {
        // called when the status of the provider changes (there are a variety of reasons for this)
    }
}

Cancelando a assinatura de atualizações do LocationManager

Para conservar os recursos do sistema, um aplicativo deve cancelar a assinatura de atualizações de local o mais rápido possível. O RemoveUpdates método diz ao para parar de LocationManager enviar atualizações para o nosso aplicativo. Como exemplo, uma Atividade pode chamar RemoveUpdates o OnPause método para que possamos economizar energia se um aplicativo não precisar de atualizações de localização enquanto sua Atividade não estiver na tela:

protected override void OnPause ()
{
    base.OnPause ();
    locationManager.RemoveUpdates (this);
}

Se o aplicativo precisar obter atualizações de localização em segundo plano, você desejará criar um Serviço personalizado que assine o Serviço de Localização do sistema. Consulte o guia Backgrounding with Android Services para obter mais informações.

Determinando o melhor provedor de localização para o LocationManager

O aplicativo acima define o GPS como o provedor de localização. No entanto, o GPS pode não estar disponível em todos os casos, como se o dispositivo estiver dentro de casa ou não tiver um receptor GPS. Se esse for o caso, o resultado será um null retorno para o Provedor.

Para fazer com que seu aplicativo funcione quando o GPS não estiver disponível, use o GetBestProvider método para solicitar o melhor provedor de localização disponível (suportado pelo dispositivo e habilitado pelo usuário) na inicialização do aplicativo. Em vez de passar um provedor específico, você pode dizer GetBestProvider os requisitos para o provedor - como precisão e potência - com um Criteria objeto. GetBestProvider retorna o melhor provedor para os Critérios fornecidos.

O código a seguir mostra como obter o melhor provedor disponível e usá-lo ao solicitar atualizações de local:

Criteria locationCriteria = new Criteria();   
locationCriteria.Accuracy = Accuracy.Coarse;
locationCriteria.PowerRequirement = Power.Medium;

locationProvider = locationManager.GetBestProvider(locationCriteria, true);

if(locationProvider != null)
{
    locationManager.RequestLocationUpdates (locationProvider, 2000, 1, this);
}
else
{
    Log.Info(tag, "No location providers available");
}

Observação

Se o usuário tiver desabilitado todos os provedores de localização, GetBestProvider retornará null. Para ver como esse código funciona em um dispositivo real, ative o GPS, o Wi-Fi e as redes celulares no Modo de localização > das Configurações > do Google, conforme mostrado nesta captura de tela:

Tela do Modo de Localização de Configurações em um telefone Android

A captura de tela abaixo demonstra o aplicativo de localização em execução usando GetBestProvider:

Aplicativo GetBestProvider exibindo latitude, longitude e provedor

Lembre-se de que GetBestProvider isso não altera o provedor dinamicamente. Em vez disso, ele determina o melhor provedor disponível uma vez durante o ciclo de vida da atividade. Se o status do provedor for alterado depois de definido, o aplicativo exigirá código adicional nos ILocationListener métodos – OnProviderEnabled, OnProviderDisablede OnStatusChanged – para lidar com todas as possibilidades relacionadas à troca de provedor.

Resumo

Este guia abordou a obtenção da localização do usuário usando o Serviço de localização do Android e o provedor de localização fundido da API dos Serviços de localização do Google.