Guida per sviluppatori Android all'API dei servizi di localizzazione di Google
Pubblicato: 2022-03-11Conoscere la posizione dell'utente è un'informazione utile in molte applicazioni che sviluppiamo e utilizziamo oggi. Esistono molte popolari applicazioni basate sulla posizione che ci semplificano la vita, oltre a cambiare il modo in cui utilizziamo questi servizi. Un esempio è l'applicazione estremamente popolare Foursquare, in cui gli utenti che frequentano un locale e fanno il check-in spesso ottengono sconti. Uber, che ti aiuta a ottenere un passaggio dal tuo cellulare a una tariffa inferiore rispetto a un normale taxi. La lista è ampia e continua a crescere.
In questo articolo, creeremo una semplice applicazione Android per determinare la latitudine e la longitudine dell'utente utilizzando l'API dei servizi di localizzazione di Google di Android. Quando si sviluppano applicazioni Android, ci sono un paio di modi per ottenere la posizione dell'utente.
Pacchetto "android.location"
Il pacchetto "android.location" è disponibile da quando è stato introdotto Android per la prima volta e ci dà accesso ai servizi di localizzazione. Questi servizi consentono alle applicazioni di ottenere aggiornamenti periodici della posizione geografica del dispositivo.
Il pacchetto fornisce due mezzi per acquisire i dati sulla posizione:
LocationManager.GPS_PROVIDER: determina la posizione utilizzando i satelliti. A seconda delle condizioni, questo provider potrebbe impiegare del tempo per restituire una correzione della posizione.
LocationManager.NETWORK_PROVIDER: determina la posizione in base alla disponibilità dei ripetitori cellulari e dei punti di accesso Wi-Fi nelle vicinanze. Questo è più veloce di GPS_PROVIDER.
Quando cerchi la posizione dell'utente devi giocare con questi fornitori e la loro disponibilità. Idealmente si ottiene la prima posizione utilizzando NETWORK_PROVIDER, che potrebbe non essere così preciso, ma è molto più veloce. Potresti quindi tentare di aumentare la precisione ascoltando una migliore correzione della posizione utilizzando GPS_PROVIDER.
Le API fornite da questo pacchetto sono di livello piuttosto basso e richiedono allo sviluppatore dell'applicazione di gestire i dettagli più fini per determinare quando richiedere i dati sulla posizione e pianificare le chiamate all'API in modo ottimizzato. Per migliorare l'esperienza degli sviluppatori con i servizi di sistema basati sulla posizione e facilitare il processo di sviluppo di applicazioni sensibili alla posizione, Google ha introdotto un nuovo modo per richiedere la posizione di un utente utilizzando Google Play Services. Offre un'API più semplice con maggiore precisione, geofencing a bassa potenza e molto altro.
API dei servizi di localizzazione di Google
L'API dei servizi di localizzazione di Google, nota anche come FusedLocationProviderApi, è il metodo consigliato da Google per ottenere la posizione di un utente. Fornisce la migliore precisione in base alle nostre esigenze. Alcuni dei vantaggi dell'utilizzo di questa API rispetto alla precedente sono:
Semplicità: a differenza della precedente API, non devi più avere a che fare con più provider. Invece, specifichi esigenze di alto livello, come "alta precisione" o "bassa potenza", e verrà adottato un approccio adeguato.
Disponibilità: offre alla tua app l'accesso immediato alla posizione migliore e più recente conosciuta. Di solito queste informazioni sono prontamente disponibili, devi solo richiederle.
Efficienza energetica: riduce al minimo l'utilizzo di energia dell'applicazione.
Versatilità: soddisfa un'ampia gamma di esigenze, dagli usi in primo piano, che richiedono dati sulla posizione estremamente accurati, agli usi in background, che richiedono solo aggiornamenti periodici della posizione con un impatto energetico trascurabile.
Costruiamo un'applicazione Android basata sulla posizione utilizzando questa API. Per questo, utilizzeremo l'IDE suggerito da Google per lo sviluppo di applicazioni Android: Android Studio. Iniziare con Android Studio è piuttosto semplice. Il loro sito Web descrive in dettaglio la procedura che coinvolge l'installazione e la configurazione di Android Studio, incluso come avviare la tua prima applicazione Android per lo sviluppo.
Android Studio dovrebbe semplificarci le cose. Tuttavia, dovremo iniziare configurando lo script di build e aggiungendo Google Play Services come dipendenza per questa applicazione. Questo può essere fatto modificando il file "build.gradle" come segue:
dependencies { compile 'com.android.support:appcompat-v7:21.0.3' compile 'com.google.android.gms:play-services:6.5.87' // Add this line }
Nel momento in cui scrivo questo articolo, l'ultima versione di Google Play Services disponibile è la 6.5.87. Assicurati di controllare sempre l'ultima versione disponibile prima di iniziare. Nel caso in cui versioni più recenti escano più avanti e tu decida di aggiornarlo per i tuoi progetti, testa tutte le funzionalità relative alla posizione rispetto a tutte le versioni di Android che stai supportando.
A questo punto, dovremmo essere in grado di iniziare a fare il lavoro vero e proprio per la nostra applicazione.
Richiesta di autorizzazione, configurazione di AndroidManifest.xml
Gli Android hanno caratteristiche di sicurezza specifiche che impedirebbero a qualsiasi applicazione arbitraria di richiedere una posizione precisa dell'utente. Per risolvere questo problema, dobbiamo modificare "AndroidManifest.xml" e aggiungere l'autorizzazione necessaria per questa applicazione:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Mentre ci siamo, dovremmo anche definire la versione di Google Play Services che stiamo utilizzando per questa applicazione:
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
Verifica della disponibilità dei servizi di Google Play
Prima di accedere alle funzionalità fornite da Google Play Services, dobbiamo verificare se sul dispositivo sono installati Google Play Services e che la versione sia quella che intendiamo utilizzare (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; }
Questo metodo verificherà la presenza di Google Play Services e, nel caso in cui il dispositivo non lo abbia installato (è raro, ma ho visto casi del genere), aprirà una finestra di dialogo con l'errore corrispondente e inviterà l'utente a installare/aggiornare Servizi di Google Play dal Google Play Store.
Dopo che l'utente ha completato la risoluzione fornita da "GooglePlayServicesUtil.getErrorDialog()", viene attivato un metodo di callback "onActivityResult()", quindi dobbiamo implementare una logica per gestire quella chiamata:
@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(); } } }
Accesso alle API di Google
Per accedere alle API di Google, dobbiamo solo compiere un altro passaggio: creare un'istanza di GoogleApiClient. Il client API di Google fornisce un punto di ingresso comune a tutti i servizi di Google Play e gestisce la connessione di rete tra il dispositivo dell'utente e ogni servizio Google. Il nostro primo passo qui è avviare la connessione. Di solito chiamo questo codice dal metodo "onCreate" dell'attività:

protected synchronized void buildGoogleApiClient() { mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); }
Concatenando una serie di chiamate al metodo, stiamo specificando l'implementazione dell'interfaccia di callback e l'API del servizio di localizzazione che vogliamo utilizzare. L'implementazione dell'interfaccia, in questo caso "questo", riceverà una risposta al metodo asincrono "connect()" quando la connessione a Google Play Services riesce, fallisce o viene sospesa. Dopo aver aggiunto questo codice, il nostro "MainActivity" dovrebbe assomigliare a questo:
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) { } }
Quindi nel nostro metodo "onStart" chiamiamo il metodo "connect" e attendiamo che venga invocato il metodo di callback "onConnected":
@Override protected void onStart() { super.onStart(); if (mGoogleApiClient != null) { mGoogleApiClient.connect(); } }
Il metodo "onConnected" sarà simile a questo:
@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(); } }
Questa richiamata viene attivata quando Google Play Services è connesso, il che significa che a quel punto dovremmo avere l'ultima posizione nota. Tuttavia, questa posizione può essere nulla (è raro ma non impossibile). In tal caso, quello che consiglio è di ascoltare gli aggiornamenti sulla posizione che verranno trattati in seguito.
Ascolto degli aggiornamenti sulla posizione
Dopo aver invocato "getLastLocation", potresti voler richiedere aggiornamenti periodici dal Fused Location Provider. A seconda dell'applicazione, questo periodo potrebbe essere breve o lungo. Ad esempio, se stai creando un'applicazione che tiene traccia della posizione di un utente mentre guida, dovrai ascoltare gli aggiornamenti a brevi intervalli. D'altra parte, se la tua applicazione riguarda la condivisione della posizione dell'utente con il suo amico, forse devi solo richiedere la posizione una volta ogni tanto.
Creare una richiesta è piuttosto semplice: puoi chiamare questo metodo all'interno del metodo "onCreate":
protected void createLocationRequest() { mLocationRequest = new LocationRequest(); mLocationRequest.setInterval(20000); mLocationRequest.setFastestInterval(5000); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); }
Istanziamo un nuovo oggetto LocationRequest. Impostare l'intervallo su 20 secondi (20000 millisecondi). Inoltre, abbiamo impostato una frequenza di aggiornamento ridotta a 5 secondi. Questo dice all'API di fornire aggiornamenti ogni 20 secondi (preferibilmente), ma se è disponibile una modifica entro un periodo di 5 secondi, dovrebbe fornire anche quello. Infine, impostiamo la priorità su "PRIORITY_HIGH_ACCURACY", tra le altre opzioni di priorità disponibili: PRIORITY_BALANCED_POWER_ACCURACY, PRIORITY_LOW_POWER, PRIORITY_NO_POWER.
Dopo aver creato la richiesta, sei pronto per iniziare ad ascoltare gli aggiornamenti della posizione dopo che il metodo "onConnected()" è stato attivato:
protected void startLocationUpdates() { LocationServices.FusedLocationApi.requestLocationUpdates( mGoogleApiClient, mLocationRequest, this); }
Non resta che implementare il metodo di callback per soddisfare l'interfaccia 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(); } }
Smetti di ascoltare gli aggiornamenti
È importante interrompere esplicitamente l'ascolto degli aggiornamenti quando non sono più necessari o se l'utente lascia l'applicazione. Il metodo seguente deve essere richiamato dall'interno della callback "onPause":
protected void stopLocationUpdates() { if (mGoogleApiClient != null) { LocationServices.FusedLocationApi.removeLocationUpdates( mGoogleApiClient, this); } }
… e disconnettendo l'API di Google:
@Override protected void onStop() { super.onStop(); if (mGoogleApiClient != null) { mGoogleApiClient.disconnect(); } }
Avvolgendo
Come puoi vedere, le idee fondamentali alla base dell'implementazione di applicazioni di rilevamento della posizione in Android sono molto semplici. Inoltre, con le API disponibili che sono sia semplici da usare che facili da capire, dovrebbe essere un gioco da ragazzi creare applicazioni di base basate sulla posizione per Android. La piccola applicazione di esempio che abbiamo creato qui ha lo scopo di dimostrare esattamente questo. Puoi trovare il codice sorgente completo per questo su GitHub. Si noti che per semplificare le cose, l'applicazione non gestisce il metodo di callback "onConnectionFailed".
Speriamo che questo tutorial ti aiuti a iniziare a utilizzare l'API dei servizi di localizzazione di Google.