1. Prima di iniziare
Android 10 e 11 offrono agli utenti un maggiore controllo sulle impostazioni l'accesso alle posizioni dei loro dispositivi.
Quando un'app eseguita su Android 11 richiede l'accesso alla posizione, gli utenti hanno a disposizione quattro opzioni:
- Consenti sempre
- Consenti solo mentre l'app è in uso (su Android 10)
- Solo una volta (in Android 11)
- Nega
Android 10
Android 11
In questo codelab, imparerai a ricevere aggiornamenti sulla posizione e a supportare la posizione su qualsiasi versione di Android, in particolare Android 10 e 11. Al termine del codelab, dovresti avere un'app che segue le best practice attuali per il recupero degli aggiornamenti della posizione.
Prerequisiti
- Dimestichezza con lo sviluppo Android
- Una certa familiarità con attività, servizi e autorizzazioni
Attività previste
- Segui le best practice per la geolocalizzazione in Android.
- Gestire le autorizzazioni di accesso alla posizione in primo piano (quando l'utente richiede all'app di accedere alla posizione del dispositivo mentre l'app è in uso).
- Modifica un'app esistente per aggiungere il supporto della richiesta di accesso alla posizione aggiungendo il codice per l'iscrizione e l'annullamento dell'iscrizione alla posizione.
- Aggiungi il supporto all'app per Android 10 e 11 aggiungendo una logica per accedere alla posizione in primo piano o durante l'uso.
Che cosa ti serve
- Android Studio 3.4 o versioni successive per eseguire il codice
- Un emulatore/dispositivo con un'anteprima per gli sviluppatori di Android 10 e 11
2. Per iniziare
Clonare il repository del progetto iniziale
Per iniziare il più rapidamente possibile, puoi creare a partire da questo progetto iniziale. Se hai installato Git, puoi semplicemente eseguire questo comando:
git clone https://github.com/android/codelab-while-in-use-location
Visita direttamente la pagina GitHub.
Se non hai Git, puoi recuperare il progetto come file ZIP:
Importa il progetto.
Apri Android Studio, seleziona "Apri un progetto Android Studio esistente" dalla schermata di benvenuto e aprire la directory del progetto.
Dopo il caricamento del progetto, potresti anche visualizzare un avviso che indica che Git non sta monitorando tutte le modifiche locali. Puoi fare clic su Ignora. Non eseguirai il push delle modifiche al repository Git.
Se ti trovi nella visualizzazione Android, nell'angolo in alto a sinistra della finestra del progetto dovresti vedere qualcosa di simile all'immagine seguente. (Se ti trovi nella vista Progetto, devi espandere il progetto per vedere lo stesso elemento.)
Sono presenti due cartelle (base
e complete
). Ciascuno di essi è noto come "modulo".
Tieni presente che Android Studio potrebbe impiegare diversi secondi per compilare il progetto in background per la prima volta. Durante questo periodo, viene visualizzato il seguente messaggio nella barra di stato nella parte inferiore di Android Studio:
Attendi che Android Studio abbia terminato l'indicizzazione e la creazione del progetto prima di apportare modifiche al codice. In questo modo, Android Studio potrà recuperare tutti i componenti necessari.
Se viene visualizzato il messaggio Ricarica per applicare le modifiche alla lingua? o un messaggio simile, seleziona Sì.
Informazioni sul progetto iniziale
Ora è tutto pronto per richiedere la posizione nell'app. Utilizza il modulo base
come punto di partenza. Durante ogni passaggio, aggiungi codice nel modulo base
. Al termine di questo codelab, il codice nel modulo base
dovrebbe corrispondere ai contenuti del modulo complete
. Il modulo complete
può essere utilizzato per controllare il tuo lavoro o come riferimento in caso di problemi.
I componenti chiave includono:
MainActivity
: UI che consente all'utente di consentire all'app di accedere alla posizione del dispositivo.LocationService
: servizio che sottoscrive e annulla l'iscrizione ai cambiamenti di posizione e si promuove a servizio in primo piano (con una notifica) se l'utente esce dall'attività dell'app. Aggiungi qui il codice della località.Util
: aggiunge funzioni di estensione per la classeLocation
e salva la posizione inSharedPreferences
(livello dati semplificato).
Configurazione dell'emulatore
Per informazioni sulla configurazione di un emulatore Android, vedi Eseguire su un emulatore.
Esegui il progetto iniziale
Esegui l'app.
- Collega il dispositivo Android al computer o avvia un emulatore. Assicurati che sul dispositivo sia installato Android 10 o versioni successive.
- Nella barra degli strumenti, seleziona la configurazione
base
dal selettore a discesa e fai clic su Esegui:
- Sul tuo dispositivo viene visualizzata la seguente app:
Potresti notare che nella schermata di output non vengono visualizzate informazioni sulla posizione. Il motivo è che non hai ancora aggiunto il codice della località.
3. Aggiunta della località
Concetti
Lo scopo di questo codelab è mostrarti come ricevere aggiornamenti sulla posizione e come supportare Android 10 e Android 11.
Tuttavia, prima di iniziare a programmare, è opportuno rivedere le nozioni di base.
Tipi di accesso alla posizione
Forse ricordi le quattro diverse opzioni per l'accesso alla posizione all'inizio del codelab. Scopri cosa significano:
- Consenti solo mentre l'app è in uso
- Questa è l'opzione consigliata per la maggior parte delle app. Chiamato anche "durante l'uso" o "solo in primo piano" questa opzione è stata aggiunta in Android 10 e consente agli sviluppatori di recuperare la posizione soltanto mentre l'app è in uso. Un'app viene considerata attiva se si verifica una delle seguenti condizioni:
- Un'attività è visibile.
- Un servizio in primo piano è in esecuzione con una notifica continua.
- Solo una volta
- Aggiunta in Android 11, analoga a Consenti solo mentre l'app è in uso, ma per un periodo di tempo limitato. Per ulteriori informazioni, vedi Autorizzazioni una tantum.
- Nega
- Questa opzione impedisce l'accesso alle informazioni sulla posizione.
- Consenti sempre
- Questa opzione consente sempre l'accesso alla posizione, ma richiede un'autorizzazione aggiuntiva per Android 10 e versioni successive. Devi inoltre assicurarti di avere un caso d'uso valido e rispettare le norme sulla località. Non tratterai questa opzione in questo codelab, in quanto è un caso d'uso più raro. Tuttavia, se hai un caso d'uso valido e vuoi capire come gestire correttamente la posizione costante, incluso l'accesso alla posizione in background, esamina l'esempio di LocationUpdatesBackgroundKotlin.
Servizi, servizi in primo piano e associazione
Per supportare completamente gli aggiornamenti della posizione Consenti solo mentre l'app è in uso, devi tenere conto del momento in cui l'utente esce dalla tua app. Se vuoi continuare a ricevere aggiornamenti in questa situazione, devi creare un Service
in primo piano e associarlo a Notification
.
Inoltre, se vuoi utilizzare lo stesso Service
per richiedere aggiornamenti della posizione quando la tua app è visibile e quando l'utente esce dall'app, devi associare/scollegare questo Service
all'elemento UI.
Poiché questo codelab è incentrato solo sulla ricezione di aggiornamenti sulla posizione, puoi trovare tutto il codice che ti serve nel corso ForegroundOnlyLocationService.kt
. Puoi sfogliare il corso e il MainActivity.kt
per vedere come interagiscono tra loro.
Per ulteriori informazioni, vedi Panoramica dei servizi e Panoramica dei servizi associati.
Autorizzazioni
Per ricevere aggiornamenti di posizione da un NETWORK_PROVIDER
o GPS_PROVIDER
, devi richiedere l'autorizzazione dell'utente dichiarando rispettivamente l'autorizzazione ACCESS_COARSE_LOCATION
o ACCESS_FINE_LOCATION
nel tuo file manifest Android. Senza queste autorizzazioni, la tua app non potrà richiedere l'accesso alla posizione in fase di runtime.
Queste autorizzazioni riguardano le richieste Solo una volta e Consenti solo mentre l'app è in uso, quando la tua app viene utilizzata su un dispositivo con Android 10 o versioni successive.
Località
La tua app può accedere all'insieme di servizi di geolocalizzazione supportati tramite i corsi del pacchetto com.google.android.gms.location
.
Dai un'occhiata alle classi principali:
FusedLocationProviderClient
- È il componente centrale del framework della posizione. Una volta creato, puoi utilizzarlo per richiedere aggiornamenti sulla posizione e ottenere l'ultima posizione nota.
LocationRequest
- Si tratta di un oggetto dati che contiene parametri di qualità del servizio per le richieste (intervalli di aggiornamenti, priorità e accuratezza). Questo viene trasmesso all'
FusedLocationProviderClient
quando richiedi aggiornamenti della posizione. LocationCallback
- Viene utilizzato per ricevere notifiche quando la posizione del dispositivo cambia o non può più essere determinata. Questo viene passato un
LocationResult
in cui puoi recuperare l'elementoLocation
da salvare nel tuo database.
Ora che hai un'idea di base di ciò che stai facendo, inizia a utilizzare il codice.
4. Aggiungi caratteristiche di localizzazione
Questo codelab è incentrato sull'opzione relativa alla posizione più comune: Consenti solo mentre l'app è in uso.
Per ricevere aggiornamenti sulla posizione, la tua app deve avere un'attività visibile o un servizio in esecuzione in primo piano (con una notifica).
Autorizzazioni
Lo scopo di questo codelab è mostrare come ricevere gli aggiornamenti di posizione, non come richiedere autorizzazioni di accesso alla posizione, quindi il codice basato sulle autorizzazioni è già stato scritto automaticamente. Se lo conosci già, puoi tranquillamente ignorarlo.
Di seguito sono riportate le informazioni principali relative alle autorizzazioni (per questa parte non è richiesta alcuna azione):
- Dichiara quale autorizzazione usi in
AndroidManifest.xml
. - Prima di tentare di accedere alle informazioni sulla posizione, controlla se l'utente ha concesso alla tua app l'autorizzazione a farlo. Se la tua app non ha ancora ricevuto l'autorizzazione, richiedi l'accesso.
- Gestisci la scelta dell'utente relativa all'autorizzazione. (Puoi visualizzare questo codice nel
MainActivity.kt
.)
Se cerchi TODO: Step 1.0, Review Permissions
in AndroidManifest.xml
o MainActivity.kt
, vedrai tutto il codice scritto per le autorizzazioni.
Per maggiori informazioni, consulta la panoramica delle autorizzazioni.
Ora inizia a scrivere il codice di posizione.
Esamina le variabili chiave necessarie per gli aggiornamenti delle sedi
Nel modulo base
, cerca TODO: Step 1.1, Review variables
nella
ForegroundOnlyLocationService.kt
.
Non sono necessarie azioni in questo passaggio. Devi solo esaminare il seguente blocco di codice, insieme ai commenti, per comprendere le classi e le variabili chiave che utilizzi per ricevere aggiornamenti sulla posizione.
// TODO: Step 1.1, Review variables (no changes).
// FusedLocationProviderClient - Main class for receiving location updates.
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
// LocationRequest - Requirements for the location updates, i.e., how often you
// should receive updates, the priority, etc.
private lateinit var locationRequest: LocationRequest
// LocationCallback - Called when FusedLocationProviderClient has a new Location.
private lateinit var locationCallback: LocationCallback
// Used only for local storage of the last known location. Usually, this would be saved to your
// database, but because this is a simplified sample without a full database, we only need the
// last location to create a Notification if the user navigates away from the app.
private var currentLocation: Location? = null
Esamina l'inizializzazione di FusedLocationProviderClient
Nel modulo base
, cerca TODO: Step 1.2, Review the FusedLocationProviderClient
nel file ForegroundOnlyLocationService.kt
. Il codice dovrebbe avere un aspetto simile al seguente:
// TODO: Step 1.2, Review the FusedLocationProviderClient.
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
Come accennato nei commenti precedenti, questa è la classe principale per ricevere aggiornamenti sulla posizione. La variabile è già stata inizializzata automaticamente, ma è importante esaminare il codice per capire come viene inizializzato. Aggiungi del codice qui in un secondo momento per richiedere aggiornamenti della posizione.
Inizializza la richiesta di posizione
- Nel modulo
base
, cercaTODO: Step 1.3, Create a LocationRequest
nel fileForegroundOnlyLocationService.kt
. - Aggiungi il seguente codice dopo il commento.
Il codice di inizializzazione LocationRequest
aggiunge i parametri di qualità del servizio aggiuntivi necessari per la tua richiesta (intervalli, tempo di attesa massimo e priorità).
// TODO: Step 1.3, Create a LocationRequest.
locationRequest = LocationRequest.create().apply {
// Sets the desired interval for active location updates. This interval is inexact. You
// may not receive updates at all if no location sources are available, or you may
// receive them less frequently than requested. You may also receive updates more
// frequently than requested if other applications are requesting location at a more
// frequent interval.
//
// IMPORTANT NOTE: Apps running on Android 8.0 and higher devices (regardless of
// targetSdkVersion) may receive updates less frequently than this interval when the app
// is no longer in the foreground.
interval = TimeUnit.SECONDS.toMillis(60)
// Sets the fastest rate for active location updates. This interval is exact, and your
// application will never receive updates more frequently than this value.
fastestInterval = TimeUnit.SECONDS.toMillis(30)
// Sets the maximum time when batched location updates are delivered. Updates may be
// delivered sooner than this interval.
maxWaitTime = TimeUnit.MINUTES.toMillis(2)
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
- Leggi i commenti per capire come funzionano.
Inizializzare LocationCallback
- Nel modulo
base
, cercaTODO: Step 1.4, Initialize the LocationCallback
nel fileForegroundOnlyLocationService.kt
. - Aggiungi il seguente codice dopo il commento.
// TODO: Step 1.4, Initialize the LocationCallback.
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
super.onLocationResult(locationResult)
// Normally, you want to save a new location to a database. We are simplifying
// things a bit and just saving it as a local variable, as we only need it again
// if a Notification is created (when the user navigates away from app).
currentLocation = locationResult.lastLocation
// Notify our Activity that a new location was added. Again, if this was a
// production app, the Activity would be listening for changes to a database
// with new locations, but we are simplifying things a bit to focus on just
// learning the location side of things.
val intent = Intent(ACTION_FOREGROUND_ONLY_LOCATION_BROADCAST)
intent.putExtra(EXTRA_LOCATION, currentLocation)
LocalBroadcastManager.getInstance(applicationContext).sendBroadcast(intent)
// Updates notification content if this service is running as a foreground
// service.
if (serviceRunningInForeground) {
notificationManager.notify(
NOTIFICATION_ID,
generateNotification(currentLocation))
}
}
}
Il LocationCallback
che crei qui è il callback che il FusedLocationProviderClient
chiamerà quando è disponibile un nuovo aggiornamento della posizione.
Nel callback, ottieni innanzitutto la posizione più recente utilizzando un oggetto LocationResult
. Successivamente, invierai a Activity
la nuova posizione utilizzando una trasmissione locale (se è attiva) oppure aggiorni Notification
se questo servizio è in esecuzione in primo piano Service
.
- Leggi i commenti per capire la funzione di ogni parte.
Abbonarsi ai cambiamenti di località
Ora che hai inizializzato tutto, devi comunicare al FusedLocationProviderClient
che vuoi ricevere gli aggiornamenti.
- Nel modulo
base
, cercaStep 1.5, Subscribe to location changes
nel fileForegroundOnlyLocationService.kt
. - Aggiungi il seguente codice dopo il commento.
// TODO: Step 1.5, Subscribe to location changes.
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper())
La chiamata requestLocationUpdates()
consente al FusedLocationProviderClient
di sapere che vuoi ricevere aggiornamenti sulla posizione.
Probabilmente riconosci i LocationRequest
e LocationCallback
che hai definito in precedenza. Consentono a FusedLocationProviderClient
di conoscere i parametri della qualità del servizio per la tua richiesta e il nome da chiamare in caso di aggiornamento. Infine, l'oggetto Looper
specifica il thread per il callback.
Potresti anche notare che questo codice si trova all'interno di un'istruzione try/catch
. Questo metodo richiede un blocco di questo tipo perché un SecurityException
si verifica quando la tua app non è autorizzata ad accedere ai dati sulla posizione.
Annullare l'iscrizione alle modifiche delle località
Quando l'app non ha più bisogno di accedere ai dati sulla posizione, è importante annullare l'iscrizione agli aggiornamenti sulla posizione.
- Nel modulo
base
, cercaTODO: Step 1.6, Unsubscribe to location changes
nel fileForegroundOnlyLocationService.kt
. - Aggiungi il seguente codice dopo il commento.
// TODO: Step 1.6, Unsubscribe to location changes.
val removeTask = fusedLocationProviderClient.removeLocationUpdates(locationCallback)
removeTask.addOnCompleteListener { task ->
if (task.isSuccessful) {
Log.d(TAG, "Location Callback removed.")
stopSelf()
} else {
Log.d(TAG, "Failed to remove Location Callback.")
}
}
Il metodo removeLocationUpdates()
configura un'attività per comunicare a FusedLocationProviderClient
che non vuoi più ricevere aggiornamenti di posizione per il tuo LocationCallback
. addOnCompleteListener()
fornisce il callback per il completamento ed esegue il Task
.
Come nel passaggio precedente, potresti aver notato che questo codice si trova all'interno di un'istruzione try/catch
. Questo metodo richiede un blocco di questo tipo perché un SecurityException
si verifica quando la tua app non ha l'autorizzazione ad accedere alle informazioni sulla posizione
È possibile che si stia chiedendo quando vengono chiamati i metodi che contengono il codice di sottoscrizione/annullamento dell'iscrizione. Vengono attivati nella classe principale quando l'utente tocca il pulsante. Se vuoi vederlo, dai un'occhiata al corso MainActivity.kt
.
Esegui app
Esegui l'app da Android Studio e prova il pulsante della posizione.
Nella schermata di output dovresti vedere le informazioni sulla posizione. Questa è un'app completamente funzionante per Android 9.
5. Supporto per Android 10
In questa sezione aggiungi il supporto per Android 10.
La tua app è già in abbonamento per il cambio di posizione, quindi non c'è molto da fare.
Anzi, devi solo specificare che il tuo servizio in primo piano viene utilizzato per scopi di localizzazione.
SDK target 29
- Nel modulo
base
, cercaTODO: Step 2.1, Target Android 10 and then Android 11.
nel filebuild.gradle
. - Apporta queste modifiche:
- Imposta
targetSdkVersion
su29
.
Il codice dovrebbe avere un aspetto simile al seguente:
android {
// TODO: Step 2.1, Target Android 10 and then Android 11.
compileSdkVersion 29
defaultConfig {
applicationId "com.example.android.whileinuselocation"
minSdkVersion 26
targetSdkVersion 29
versionCode 1
versionName "1.0"
}
...
}
Dopodiché ti verrà chiesto di sincronizzare il progetto. Fai clic su Sincronizza ora.
Dopodiché, la tua app è quasi pronta per Android 10.
Aggiungi tipo di servizio in primo piano
Se hai bisogno dell'accesso alla posizione in uso, in Android 10 devi includere il tipo di servizio in primo piano. Nel tuo caso, viene utilizzato per ottenere informazioni sulla posizione.
Nel modulo base
, cerca TODO: 2.2, Add foreground service type
in AndroidManifest.xml
e aggiungi il seguente codice all'elemento <service>
:
android:foregroundServiceType="location"
Il codice dovrebbe avere un aspetto simile al seguente:
<application>
...
<!-- Foreground services in Android 10+ require type. -->
<!-- TODO: 2.2, Add foreground service type. -->
<service
android:name="com.example.android.whileinuselocation.ForegroundOnlyLocationService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="location" />
</application>
È tutto. La tua app supporta la posizione di Android 10 per l'utilizzo seguendo le best practice per la geolocalizzazione in Android.
Esegui app
Esegui l'app da Android Studio e prova il pulsante della posizione.
Tutto dovrebbe funzionare come prima, ma ora funziona su Android 10. Se non hai già accettato le autorizzazioni per le località, ora dovresti visualizzare la schermata delle autorizzazioni.
6. Supporto per Android 11
In questa sezione, scegli come target Android 11.
Ottime notizie, non è necessario apportare modifiche a nessun file, ad eccezione del file build.gradle
.
SDK target 11
- Nel modulo
base
, cercaTODO: Step 2.1, Target SDK
nel filebuild.gradle
. - Apporta queste modifiche:
- Da
compileSdkVersion
a30
- Da
targetSdkVersion
a30
Il codice dovrebbe avere un aspetto simile al seguente:
android {
TODO: Step 2.1, Target Android 10 and then Android 11.
compileSdkVersion 30
defaultConfig {
applicationId "com.example.android.whileinuselocation"
minSdkVersion 26
targetSdkVersion 30
versionCode 1
versionName "1.0"
}
...
}
Dopodiché ti verrà chiesto di sincronizzare il progetto. Fai clic su Sincronizza ora.
Dopodiché, la tua app sarà pronta per Android 11.
Esegui app
Esegui l'app da Android Studio e prova a fare clic sul pulsante.
Tutto dovrebbe funzionare come prima, ma ora funziona su Android 11. Se non hai già accettato le autorizzazioni per le località, ora dovresti visualizzare la schermata delle autorizzazioni.
7. Strategie di geolocalizzazione per Android
Controllando e richiedendo le autorizzazioni di accesso alla posizione nei modi mostrati in questo codelab, la tua app può monitorare correttamente il proprio livello di accesso relativo alla posizione del dispositivo.
In questa pagina sono elencate alcune best practice chiave relative alle autorizzazioni di accesso alla posizione. Per ulteriori informazioni su come mantenere le impostazioni sicurezza dei dati, consulta le Best practice per le autorizzazioni app.
Chiedi solo le autorizzazioni che ti servono
Chiedi le autorizzazioni solo quando è necessario. Ad esempio:
- Non richiedere un'autorizzazione di accesso alla posizione all'avvio dell'app, a meno che non sia assolutamente necessario.
- Se la tua app ha come target Android 10 o versioni successive e disponi di un servizio in primo piano, dichiara un valore
foregroundServiceType
di"location"
nel file manifest. - Non richiedere autorizzazioni di accesso alla posizione in background a meno che tu non abbia un caso d'uso valido come descritto nella sezione Accesso più sicuro e trasparente alla posizione dell'utente.
Supporta la riduzione controllata se l'autorizzazione non viene concessa
Per garantire una buona esperienza utente, progetta la tua app in modo che possa gestire senza problemi le seguenti situazioni:
- La tua app non ha accesso alle informazioni sulla posizione.
- La tua app non ha accesso ai dati sulla posizione quando viene eseguita in background.
8. Complimenti
Hai imparato a ricevere aggiornamenti sulla posizione su Android, tenendo presenti le best practice.
Scopri di più
- Esempio completo per l'utilizzo della posizione in background se hai un caso d'uso valido
- Richiedere aggiornamenti sulla posizione