Guia do desenvolvedor Android para a API de serviços de localização do Google
Publicados: 2022-03-11Saber a localização do seu usuário é uma informação útil em muitos aplicativos que desenvolvemos e usamos hoje. Existem muitos aplicativos populares baseados em localização por aí que estão facilitando nossas vidas, além de mudar a maneira como usamos esses serviços. Um exemplo é o popular aplicativo Foursquare, onde os usuários que freqüentam um estabelecimento e fazem “check-in” muitas vezes ganham descontos. Uber, que ajuda você a pegar uma carona do seu celular a uma taxa mais baixa do que um táxi normal. A lista é grande e continua crescendo.
Neste artigo, vamos construir um aplicativo Android simples para determinar a latitude e longitude do usuário usando a API do Google Location Services do Android. Ao desenvolver aplicativos Android, existem algumas maneiras de obter a localização do usuário.
Pacote “android.location”
O pacote “android.location” está disponível desde o lançamento do Android e nos dá acesso a serviços de localização. Esses serviços permitem que os aplicativos obtenham atualizações periódicas da localização geográfica do dispositivo.
O pacote fornece dois meios de aquisição de dados de localização:
LocationManager.GPS_PROVIDER: Determina a localização usando satélites. Dependendo das condições, esse provedor pode demorar um pouco para retornar uma correção de local.
LocationManager.NETWORK_PROVIDER: determina a localização com base na disponibilidade de torres de celular próximas e pontos de acesso WiFi. Isso é mais rápido que GPS_PROVIDER.
Quando você procura a localização do usuário, precisa jogar com esses provedores e sua disponibilidade. Idealmente, você obtém o primeiro local usando NETWORK_PROVIDER, que pode não ser tão preciso, mas é muito mais rápido. Você pode tentar aumentar a precisão ouvindo uma melhor localização usando o GPS_PROVIDER.
As APIs fornecidas por este pacote são de nível bastante baixo e exigem que o desenvolvedor do aplicativo lide com os detalhes mais sutis de determinar quando solicitar dados de localização e agendar chamadas para a API de maneira otimizada. Para melhorar a experiência do desenvolvedor com serviços de sistema baseados em localização e facilitar o processo de desenvolvimento de aplicativos com reconhecimento de localização, o Google introduziu uma nova maneira de solicitar a localização de um usuário usando o Google Play Services. Ele oferece uma API mais simples com maior precisão, geofencing de baixo consumo e muito mais.
API de serviços de localização do Google
A API de serviços de localização do Google, também conhecida como FusedLocationProviderApi, é a maneira recomendada pelo Google de obter a localização de um usuário. Ele fornece a melhor precisão com base em nossas necessidades. Algumas das vantagens de usar esta API sobre a anterior são:
Simplicidade: Ao contrário da API anterior, você não precisa mais lidar com vários provedores. Em vez disso, você especifica necessidades de alto nível, como “alta precisão” ou “baixa potência”, e será adotada uma abordagem adequada.
Disponibilidade: dá ao seu aplicativo acesso imediato ao melhor e mais recente local conhecido. Normalmente esta informação está prontamente disponível, você só tem que pedir.
Eficiência de energia: Minimiza o uso de energia do seu aplicativo.
Versatilidade: atende a uma ampla gama de necessidades, desde usos em primeiro plano - que precisam de dados de localização altamente precisos, até usos em segundo plano - exigindo apenas atualizações periódicas de localização com impacto de energia insignificante.
Vamos construir um aplicativo Android baseado em localização usando esta API. Para isso, usaremos o IDE sugerido pelo Google para desenvolvimento de aplicativos Android - Android Studio. Começar com o Android Studio é bastante simples. O site deles descreve detalhadamente o procedimento que envolve a instalação e configuração do Android Studio, incluindo como inicializar seu primeiro aplicativo Android para desenvolvimento.
O Android Studio deve tornar as coisas super fáceis para nós. No entanto, precisaremos começar configurando o script de compilação e adicionando o Google Play Services como uma dependência para este aplicativo. Isso pode ser feito modificando o arquivo “build.gradle” da seguinte forma:
dependencies { compile 'com.android.support:appcompat-v7:21.0.3' compile 'com.google.android.gms:play-services:6.5.87' // Add this line }
No momento em que escrevo este artigo, a versão mais recente do Google Play Services disponível é a 6.5.87. Certifique-se de sempre verificar a versão mais recente disponível antes de começar. Caso as versões mais recentes sejam lançadas posteriormente e você decida atualizá-las para seus próprios projetos, teste todos os recursos relacionados à localização em todas as versões do Android que você suporta.
Neste ponto, devemos ser capazes de começar a fazer o trabalho real para nosso aplicativo.
Solicitando permissão, configurando AndroidManifest.xml
Os Androids têm recursos de segurança específicos que impediriam qualquer aplicativo arbitrário de solicitar uma localização precisa do usuário. Para resolver isso, precisamos editar “AndroidManifest.xml” e adicionar a permissão necessária para este aplicativo:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Enquanto estamos nisso, também devemos definir a versão do Google Play Services que estamos usando para este aplicativo:
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
Verificando a disponibilidade do Google Play Services
Antes de acessar os recursos fornecidos pelo Google Play Services, devemos verificar se o dispositivo possui o Google Play Services instalado e se a versão é a que pretendemos usar (6.5.87).
private boolean checkGooglePlayServices(){ int checkGooglePlayServices = GooglePlayServicesUtil .isGooglePlayServicesAvailable(mContext); if (checkGooglePlayServices != ConnectionResult.SUCCESS) { /* * Google Play Services is missing or update is required * return code could be * SUCCESS, * SERVICE_MISSING, SERVICE_VERSION_UPDATE_REQUIRED, * SERVICE_DISABLED, SERVICE_INVALID. */ GooglePlayServicesUtil.getErrorDialog(checkGooglePlayServices, mContext, REQUEST_CODE_RECOVER_PLAY_SERVICES).show(); return false; } return true; }
Este método verificará o Google Play Services e, caso o dispositivo não o tenha instalado (é raro, mas já vi casos), ele abrirá uma caixa de diálogo com o erro correspondente e convidará o usuário a instalar/atualizar Serviços do Google Play da Google Play Store.
Depois que o usuário conclui a resolução fornecida por “GooglePlayServicesUtil.getErrorDialog()”, um método de retorno de chamada “onActivityResult()” é acionado, então temos que implementar alguma lógica para lidar com essa chamada:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_RECOVER_PLAY_SERVICES) { if (resultCode == RESULT_OK) { // Make sure the app is not already connected or attempting to connect if (!mGoogleApiClient.isConnecting() && !mGoogleApiClient.isConnected()) { mGoogleApiClient.connect(); } } else if (resultCode == RESULT_CANCELED) { Toast.makeText(mContext, "Google Play Services must be installed.", Toast.LENGTH_SHORT).show(); finish(); } } }
Acessando as APIs do Google
Para acessar as APIs do Google, basta realizar mais uma etapa: criar uma instância de GoogleApiClient. O Google API Client fornece um ponto de entrada comum para todos os serviços do Google Play e gerencia a conexão de rede entre o dispositivo do usuário e cada serviço do Google. Nosso primeiro passo aqui é iniciar a conexão. Eu costumo chamar esse código do método “onCreate” da atividade:
protected synchronized void buildGoogleApiClient() { mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); }
Ao encadear uma série de chamadas de método, estamos especificando a implementação da interface de retorno de chamada e a API do serviço de localização que queremos usar. A implementação da interface, neste caso “this”, receberá resposta ao método assíncrono “connect()” quando a conexão com o Google Play Services for bem-sucedida, falhar ou for suspensa. Após adicionar este código, nossa “MainActivity” deve ficar assim:

package com.bitwoo.userlocation; import android.content.Intent; import android.location.Location; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.location.LocationServices; public class MainActivity extends ActionBarActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { private static int REQUEST_CODE_RECOVER_PLAY_SERVICES = 200; private GoogleApiClient mGoogleApiClient; private Location mLastLocation; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (checkGooglePlayServices()) { buildGoogleApiClient(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } private boolean checkGooglePlayServices() { int checkGooglePlayServices = GooglePlayServicesUtil .isGooglePlayServicesAvailable(this); if (checkGooglePlayServices != ConnectionResult.SUCCESS) { /* * google play services is missing or update is required * return code could be * SUCCESS, * SERVICE_MISSING, SERVICE_VERSION_UPDATE_REQUIRED, * SERVICE_DISABLED, SERVICE_INVALID. */ GooglePlayServicesUtil.getErrorDialog(checkGooglePlayServices, this, REQUEST_CODE_RECOVER_PLAY_SERVICES).show(); return false; } return true; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_RECOVER_PLAY_SERVICES) { if (resultCode == RESULT_OK) { // Make sure the app is not already connected or attempting to connect if (!mGoogleApiClient.isConnecting() && !mGoogleApiClient.isConnected()) { mGoogleApiClient.connect(); } } else if (resultCode == RESULT_CANCELED) { Toast.makeText(this, "Google Play Services must be installed.", Toast.LENGTH_SHORT).show(); finish(); } } } protected synchronized void buildGoogleApiClient() { mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); } @Override public void onConnected(Bundle bundle) { } @Override public void onConnectionSuspended(int i) { } @Override public void onConnectionFailed(ConnectionResult connectionResult) { } }
Então, em nosso método “onStart”, chamamos o método “connect” e esperamos que o método de retorno de chamada “onConnected” seja invocado:
@Override protected void onStart() { super.onStart(); if (mGoogleApiClient != null) { mGoogleApiClient.connect(); } }
O método “onConnected” ficará assim:
@Override public void onConnected(Bundle bundle) { mLastLocation = LocationServices.FusedLocationApi.getLastLocation( mGoogleApiClient); if (mLastLocation != null) { Toast.makeText(this, "Latitude:" + mLastLocation.getLatitude()+", Longitude:"+mLastLocation.getLongitude(),Toast.LENGTH_LONG).show(); } }
Esse retorno de chamada é acionado quando o Google Play Services está conectado, o que significa que devemos ter o último local conhecido. No entanto, esse local pode ser nulo (é raro, mas não impossível). Nesse caso, o que eu recomendo é ouvir as atualizações de localização que serão abordadas a seguir.
Ouvindo atualizações de local
Depois de invocar “getLastLocation”, talvez você queira solicitar atualizações periódicas do Fused Location Provider. Dependendo da sua aplicação, esse período pode ser curto ou longo. Por exemplo, se você estiver construindo um aplicativo que rastreia a localização de um usuário enquanto ele dirige, você precisará ouvir atualizações em intervalos curtos. Por outro lado, se o seu aplicativo é sobre compartilhar a localização do usuário com o amigo dele, talvez você só precise solicitar a localização de vez em quando.
Criar uma solicitação é bem fácil - você pode chamar esse método dentro do método “onCreate”:
protected void createLocationRequest() { mLocationRequest = new LocationRequest(); mLocationRequest.setInterval(20000); mLocationRequest.setFastestInterval(5000); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); }
Instanciamos um novo objeto LocationRequest. Defina o intervalo para 20 segundos (20.000 milissegundos). Além disso, definimos uma taxa de atualização limitada para 5 segundos. Isso diz à API para fornecer atualizações a cada 20 segundos (de preferência), mas se houver uma alteração disponível em um período de 5 segundos, ela também deve ser fornecida. Por fim, definimos a prioridade para “PRIORITY_HIGH_ACCURACY”, entre as outras opções de prioridade disponíveis: PRIORITY_BALANCED_POWER_ACCURACY, PRIORITY_LOW_POWER, PRIORITY_NO_POWER.
Depois de criar a solicitação, você está pronto para começar a ouvir as atualizações de localização após o método “onConnected()” ser acionado:
protected void startLocationUpdates() { LocationServices.FusedLocationApi.requestLocationUpdates( mGoogleApiClient, mLocationRequest, this); }
Tudo o que resta agora é implementar o método de retorno de chamada para satisfazer a interface LocationListener:
public class MainActivity extends ActionBarActivity implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener { // ... @Override public void onLocationChanged(Location location) { mLastLocation = location; Toast.makeText(this, "Latitude:" + mLastLocation.getLatitude()+", Longitude:"+mLastLocation.getLongitude(),Toast.LENGTH_LONG).show(); } }
Pare de ouvir atualizações
É importante parar explicitamente de ouvir atualizações quando você não precisar mais delas ou se o usuário sair do seu aplicativo. O método a seguir deve ser invocado de dentro do retorno de chamada “onPause”:
protected void stopLocationUpdates() { if (mGoogleApiClient != null) { LocationServices.FusedLocationApi.removeLocationUpdates( mGoogleApiClient, this); } }
… e desconectando a API do Google:
@Override protected void onStop() { super.onStop(); if (mGoogleApiClient != null) { mGoogleApiClient.disconnect(); } }
Empacotando
Como você pode ver, as ideias fundamentais por trás da implementação de aplicativos com reconhecimento de localização no Android são muito simples. Além disso, com as APIs disponíveis que são simples de usar e fáceis de entender, deve ser fácil criar aplicativos básicos baseados em localização para Android. O pequeno aplicativo de exemplo que construímos aqui pretende demonstrar exatamente isso. Você pode encontrar o código-fonte completo para isso no GitHub. Observe que, para simplificar, o aplicativo não está manipulando o método de retorno de chamada “onConnectionFailed”.
Espero que este tutorial ajude você a começar a usar a API de serviços de localização do Google.