Il geofencing combina la consapevolezza della posizione attuale dell'utente con quella della sua vicinanza a località che potrebbero essere di tuo interesse. Per contrassegnare un località di interesse, devi specificare la latitudine e la longitudine. Per regolare la prossimità del località, aggiungi un raggio. La latitudine, la longitudine e il raggio definiscono un recinto virtuale, creando un un'area circolare, o recinzione, intorno al luogo di interesse.
Puoi avere più recinti virtuali attivi, con un limite di 100 per app e per utente del dispositivo. Per ogni recinto virtuale, puoi chiedere ai Servizi di geolocalizzazione di inviarti gli eventi di ingresso e uscita oppure specificare il tempo di attesa (dwell) all'interno dell'area del recinto virtuale prima di attivare un evento. Tu può limitare la durata di qualsiasi recinto virtuale specificando una durata in millisecondi. Alla scadenza del recinto virtuale, i servizi di geolocalizzazione lo rimuoveranno automaticamente.
Questa lezione ti mostra come aggiungere e rimuovere recinti virtuali e come riconoscere le transizioni corrispondenti
utilizzando un BroadcastReceiver
.
Nota:sui dispositivi Wear, le API Geofencing non fanno un uso efficiente delle corrente. Sconsigliamo di usare queste API su Wear. Letto Per ulteriori informazioni, risparmio energetico e batteria.
Configura per il monitoraggio del recinto virtuale
Il primo passaggio per richiedere il monitoraggio del recinto virtuale è richiedere le autorizzazioni aggiuntive. Per utilizzare il geofencing, la tua app deve richiedere quanto segue:
-
ACCESS_FINE_LOCATION
-
ACCESS_BACKGROUND_LOCATION
se la tua app ha come target Android 10 (livello API 29) o versioni successive
Per ulteriori informazioni, consulta la guida su come richiedere le autorizzazioni di accesso alla posizione.
Se vuoi usare BroadcastReceiver
per rilevare le transizioni del recinto virtuale,
aggiungi un elemento
che specifica il nome del servizio. Questo elemento deve essere
un elemento secondario di
<application>
:
<application android:allowBackup="true"> ... <receiver android:name=".GeofenceBroadcastReceiver"/> <application/>
Per accedere alle API di posizione, devi creare un'istanza del metodo Client di geofencing. Per scoprire come collegare il tuo client:
Kotlin
lateinit var geofencingClient: GeofencingClient override fun onCreate(savedInstanceState: Bundle?) { // ... geofencingClient = LocationServices.getGeofencingClient(this) }
Java
private GeofencingClient geofencingClient; @Override public void onCreate(Bundle savedInstanceState) { // ... geofencingClient = LocationServices.getGeofencingClient(this); }
Crea e aggiungi recinti virtuali
La tua app deve creare e aggiungere recinti virtuali utilizzando la classe del builder dell'API di posizione per
creazione di oggetti del recinto virtuale e la classe di convenienza per aggiungerli. Inoltre, per gestire
per intent inviati dai Servizi di geolocalizzazione quando si verificano transizioni con recinto virtuale, puoi definire
PendingIntent
come mostrato in questa sezione.
Nota:sui dispositivi di un singolo utente, esiste un limite di 100 recinti virtuali per app. Per i dispositivi multiutente, il limite è di 100 recinti virtuali per app per utente di dispositivo.
Crea oggetti del recinto virtuale
Innanzitutto, usa
Geofence.Builder
per creare un recinto virtuale, impostando il raggio, la durata e
tipi di transizione per il recinto virtuale. Ad esempio, per compilare un oggetto elenco:
Kotlin
geofenceList.add(Geofence.Builder() // Set the request ID of the geofence. This is a string to identify this // geofence. .setRequestId(entry.key) // Set the circular region of this geofence. .setCircularRegion( entry.value.latitude, entry.value.longitude, Constants.GEOFENCE_RADIUS_IN_METERS ) // Set the expiration duration of the geofence. This geofence gets automatically // removed after this period of time. .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS) // Set the transition types of interest. Alerts are only generated for these // transition. We track entry and exit transitions in this sample. .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_EXIT) // Create the geofence. .build())
Java
geofenceList.add(new Geofence.Builder() // Set the request ID of the geofence. This is a string to identify this // geofence. .setRequestId(entry.getKey()) .setCircularRegion( entry.getValue().latitude, entry.getValue().longitude, Constants.GEOFENCE_RADIUS_IN_METERS ) .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS) .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT) .build());
Questo esempio estrae i dati da un file di costanti. In pratica, le app potrebbero creare dinamicamente recinti virtuali in base alla località dell'utente.
Specifica i recinti virtuali e i trigger iniziali
Il seguente snippet utilizza la classe
GeofencingRequest
e la relativa classe
GeofencingRequestBuilder
nidificata
specificare i recinti virtuali da monitorare e impostare la modalità di attivazione degli eventi del recinto virtuale:
Kotlin
private fun getGeofencingRequest(): GeofencingRequest { return GeofencingRequest.Builder().apply { setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER) addGeofences(geofenceList) }.build() }
Java
private GeofencingRequest getGeofencingRequest() { GeofencingRequest.Builder builder = new GeofencingRequest.Builder(); builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER); builder.addGeofences(geofenceList); return builder.build(); }
Questo esempio mostra l'uso di due trigger per il recinto virtuale.
GEOFENCE_TRANSITION_ENTER
la transizione si attiva quando un dispositivo entra in un recinto virtuale e l'
GEOFENCE_TRANSITION_EXIT
si attiva quando un dispositivo esce da un recinto virtuale. Specificare
INITIAL_TRIGGER_ENTER
indica ai Servizi di geolocalizzazione che
GEOFENCE_TRANSITION_ENTER
dovrebbe attivarsi se il dispositivo si trova già all'interno del recinto virtuale.
In molti casi, è preferibile utilizzare invece
INITIAL_TRIGGER_DWELL
,
che attiva gli eventi solo quando l'utente si ferma per un periodo di tempo definito all'interno di un recinto virtuale.
Questo approccio contribuisce a ridurre gli avvisi di spam derivanti da notifiche di grandi numeri quando
il dispositivo entra ed esce per un breve periodo da geofencing. Un'altra strategia per ottenere i migliori risultati
il recinto virtuale consiste nell'impostare un raggio minimo di 100 metri. Questo aiuta a tenere conto della precisione della posizione
delle reti Wi-Fi tipiche e consente inoltre di ridurre il consumo energetico del dispositivo.
Definisci un broadcast receiver per le transizioni del recinto virtuale
Un Intent
inviato dai Servizi di geolocalizzazione può attivare varie azioni in
dell'app, ma non deve avviare un'attività o un frammento, poiché i componenti
devono diventare visibili solo in risposta a un'azione dell'utente. In molti casi, un BroadcastReceiver
è un buon modo per gestire una transizione del recinto virtuale. R
BroadcastReceiver
riceve aggiornamenti quando si verifica un evento, ad esempio una
transizione dentro o fuori da un recinto virtuale e può avviare uno sfondo a lunga esecuzione
al lavoro.
Il seguente snippet mostra come
per definire un PendingIntent
che avvia un BroadcastReceiver
:
Kotlin
class MainActivity : AppCompatActivity() { // ... private val geofencePendingIntent: PendingIntent by lazy { val intent = Intent(this, GeofenceBroadcastReceiver::class.java) // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling // addGeofences() and removeGeofences(). PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) } }
Java
public class MainActivity extends AppCompatActivity { // ... private PendingIntent getGeofencePendingIntent() { // Reuse the PendingIntent if we already have it. if (geofencePendingIntent != null) { return geofencePendingIntent; } Intent intent = new Intent(this, GeofenceBroadcastReceiver.class); // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when // calling addGeofences() and removeGeofences(). geofencePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent. FLAG_UPDATE_CURRENT); return geofencePendingIntent; }
Aggiungi recinti virtuali
Per aggiungere recinti virtuali, utilizza il metodo
.
Fornisci l'oggetto GeofencingClient.addGeofences()
GeofencingRequest
e il PendingIntent
.
Lo snippet seguente mostra l'elaborazione dei risultati:
Kotlin
geofencingClient?.addGeofences(getGeofencingRequest(), geofencePendingIntent)?.run { addOnSuccessListener { // Geofences added // ... } addOnFailureListener { // Failed to add geofences // ... } }
Java
geofencingClient.addGeofences(getGeofencingRequest(), getGeofencePendingIntent()) .addOnSuccessListener(this, new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { // Geofences added // ... } }) .addOnFailureListener(this, new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Failed to add geofences // ... } });
Gestire le transizioni del recinto virtuale
Quando i servizi di geolocalizzazione rilevano che l'utente è entrato o uscito da un recinto virtuale,
invia il valore Intent
contenuto in PendingIntent
incluso nella richiesta di aggiunta di recinti virtuali. Un broadcast receiver come
GeofenceBroadcastReceiver
nota che Intent
è stato richiamato e
può quindi ottenere l'evento di geofencing dall'intento, determinare il tipo di transizione o le transizioni del recinto virtuale,
e determinare quale dei recinti geografici definiti è stato attivato. La trasmissione
il destinatario può indirizzare un'app per iniziare a eseguire lavori in background o,
desiderato, inviare una notifica come output.
Nota: su Android 8.0 (livello API 26) e versioni successive, se un'app sia in esecuzione in background mentre monitora un recinto virtuale, il dispositivo risponde agli eventi di geofencing ogni due minuti. Per imparare ad adattare la tua app a questi limiti di risposta, vedi Premessa Limiti di località.
Il seguente snippet mostra come definire un
BroadcastReceiver
che pubblica una notifica quando si verifica una transizione dal recinto virtuale. Quando l'utente
fa clic sulla notifica, viene visualizzata l'attività principale dell'app:
Kotlin
class GeofenceBroadcastReceiver : BroadcastReceiver() { // ... override fun onReceive(context: Context?, intent: Intent?) { val geofencingEvent = GeofencingEvent.fromIntent(intent) if (geofencingEvent.hasError()) { val errorMessage = GeofenceStatusCodes .getStatusCodeString(geofencingEvent.errorCode) Log.e(TAG, errorMessage) return } // Get the transition type. val geofenceTransition = geofencingEvent.geofenceTransition // Test that the reported transition was of interest. if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER | geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) { // Get the geofences that were triggered. A single event can trigger // multiple geofences. val triggeringGeofences = geofencingEvent.triggeringGeofences // Get the transition details as a String. val geofenceTransitionDetails = getGeofenceTransitionDetails( this, geofenceTransition, triggeringGeofences ) // Send notification and log the transition details. sendNotification(geofenceTransitionDetails) Log.i(TAG, geofenceTransitionDetails) } else { // Log the error. Log.e(TAG, getString(R.string.geofence_transition_invalid_type, geofenceTransition)) } } }
Java
public class GeofenceBroadcastReceiver extends BroadcastReceiver { // ... protected void onReceive(Context context, Intent intent) { GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent); if (geofencingEvent.hasError()) { String errorMessage = GeofenceStatusCodes .getStatusCodeString(geofencingEvent.getErrorCode()); Log.e(TAG, errorMessage); return; } // Get the transition type. int geofenceTransition = geofencingEvent.getGeofenceTransition(); // Test that the reported transition was of interest. if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER || geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) { // Get the geofences that were triggered. A single event can trigger // multiple geofences. List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences(); // Get the transition details as a String. String geofenceTransitionDetails = getGeofenceTransitionDetails( this, geofenceTransition, triggeringGeofences ); // Send notification and log the transition details. sendNotification(geofenceTransitionDetails); Log.i(TAG, geofenceTransitionDetails); } else { // Log the error. Log.e(TAG, getString(R.string.geofence_transition_invalid_type, geofenceTransition)); } } }
Dopo aver rilevato l'evento di transizione tramite PendingIntent
,
BroadcastReceiver
ottiene il tipo di transizione del recinto virtuale
verifica se si tratta di uno degli eventi utilizzati dall'app per attivare
notifiche,
GEOFENCE_TRANSITION_ENTER
o GEOFENCE_TRANSITION_EXIT
in questo caso. Il servizio invia quindi una notifica e registra i dettagli della transizione.
Interrompi il monitoraggio del recinto virtuale
Interrompere il monitoraggio del recinto virtuale quando non è più necessario o desiderato può aiutare a risparmiare batteria
l'accensione e i cicli della CPU sul dispositivo. Puoi interrompere il monitoraggio del recinto virtuale
nell'attività principale utilizzata per aggiungere e rimuovere recinti virtuali; la rimozione di un recinto virtuale la interrompe
immediatamente. L'API fornisce metodi per
rimuovi i recinti virtuali tramite ID richiesta o rimuovendo i recinti virtuali associati a un determinato
PendingIntent
.
Il seguente snippet rimuove i recinti virtuali di PendingIntent
, interrompendo tutto
Ulteriore notifica quando il dispositivo entra o esce da recinti virtuali aggiunti in precedenza:
Kotlin
geofencingClient?.removeGeofences(geofencePendingIntent)?.run { addOnSuccessListener { // Geofences removed // ... } addOnFailureListener { // Failed to remove geofences // ... } }
Java
geofencingClient.removeGeofences(getGeofencePendingIntent()) .addOnSuccessListener(this, new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { // Geofences removed // ... } }) .addOnFailureListener(this, new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Failed to remove geofences // ... } });
Puoi combinare il geofencing con altre funzionalità sensibili alla posizione, ad esempio gli aggiornamenti periodici della posizione. Per ulteriori informazioni, vedi le altre lezioni di questo corso.
Utilizza le best practice per il geofencing
Questa sezione fornisce suggerimenti per l'utilizzo del geofencing con la località. API per Android.
Riduci il consumo di corrente
Puoi usare le seguenti tecniche per ottimizzare il consumo energetico nelle app che usano il geofencing:
Imposta il parametro reattività delle notifiche a un valore più alto. In questo modo si migliora il consumo energetico aumentando la latenza degli avvisi per recinto virtuale. Ad esempio, se imposti un valore di reattività pari a cinque minuti, la tua app verifica la presenza di un avviso di ingresso o uscita solo una volta ogni cinque minuti. L'impostazione di valori più bassi non significa necessariamente che gli utenti ricevano una notifica entro questo periodo di tempo. (ad esempio, se imposti un valore di 5 secondi, potrebbe essere necessario più tempo per ricevere il ).
Utilizza un raggio del recinto virtuale più ampio per le località in cui un utente trascorre molto tempo. come casa o lavoro. Mentre un raggio più ampio non riduce direttamente il consumo energetico, riduce la frequenza con cui l'app controlla l'entrata o l'uscita, riducendo di fatto la potenza complessiva il consumo eccessivo.
Scegli il raggio ottimale per il tuo recinto virtuale
Per ottenere risultati ottimali, il raggio minimo del recinto virtuale deve essere impostato tra 100 e 150 metri. Quando è disponibile il Wi-Fi, la precisione della posizione è compresa tra 20 e 50 metri. In ambienti interni la posizione è disponibile, il campo di precisione può essere di massimo 5 metri. A meno che tu non lo sappia in ambienti interni la posizione è disponibile all'interno del recinto virtuale, supponiamo che la precisione della geolocalizzazione del Wi-Fi riguardi 50 metri.
Se la posizione Wi-Fi non è disponibile (ad esempio, quando guidi in zone rurali), la precisione della geolocalizzazione peggiora. Il raggio di precisione può arrivare da diverse centinaia di metri a per diversi chilometri. In casi come questo, devi creare recinti virtuali utilizzando un raggio più ampio.
Spiegare agli utenti perché la tua app utilizza il geofencing
Poiché la tua app accede alla posizione in background quando utilizzi il geofencing, valuta in che modo la tua app offre vantaggi agli utenti. Spiega loro chiaramente perché la tua app ha bisogno di questo accesso per migliorare la comprensione e la trasparenza da parte degli utenti.
Per ulteriori informazioni sulle best practice relative all'accesso alla posizione, incluso il geofencing, consulta le migliori informazioni alla pagina di best practice.
Utilizzare il tipo di transizione di attesa per ridurre lo spam di avvisi
Se ricevi molti avvisi mentre guidi per brevi intervalli lungo un recinto virtuale, il modo migliore per
ridurre gli avvisi è utilizzare un tipo di transizione di
GEOFENCE_TRANSITION_DWELL
anziché
GEOFENCE_TRANSITION_ENTER
. In questo modo, l'avviso relativo alle abitazioni viene inviato solo quando l'utente si ferma
all'interno di un recinto virtuale per un determinato periodo di tempo. Puoi scegliere la durata impostando un valore
ritardo.
Registra di nuovo i recinti geografici solo quando necessario
I recinti virtuali registrati vengono conservati nel processo com.google.process.location
di proprietà di
il pacchetto com.google.android.gms
.
L'app non deve fare nulla per gestire i seguenti eventi perché il sistema
ripristina i recinti virtuali dopo questi eventi:
- È stato eseguito l'upgrade di Google Play Services.
- Google Play Services viene interrotto e riavviato dal sistema a causa della limitazione delle risorse.
- La procedura di localizzazione ha un arresto anomalo.
L'app deve registrare di nuovo i recinti geografici se sono ancora necessari dopo i seguenti eventi, poiché il sistema non può recuperare i recinti virtuali nei seguenti casi:
- Il dispositivo è stato riavviato. L'app dovrebbe ascoltare l'azione completa di avvio del dispositivo e poi ripetere. registrare i recinti virtuali richiesti.
- L'app viene disinstallata e reinstallata.
- I dati dell'app sono stati cancellati.
- I dati di Google Play Services sono stati cancellati.
- L'app ha ricevuto:
GEOFENCE_NOT_AVAILABLE
avviso. Questo accade in genere dopo la disattivazione della funzione NLP (Network Location Provider, provider di geolocalizzazione di rete di Android).
Risolvere i problemi relativi all'evento di ingresso del recinto virtuale
Se il recinto virtuale non viene attivato quando il dispositivo entra in un recinto virtuale
(l'avviso
GEOFENCE_TRANSITION_ENTER
non viene attivato), assicurati innanzitutto che i recinti virtuali siano
registrati correttamente, come descritto in questa guida.
Ecco alcuni possibili motivi per cui gli avvisi non funzionano come previsto:
- La posizione esatta non è disponibile all'interno del tuo recinto virtuale o lo è anche il tuo recinto virtuale piccolo. Sulla maggior parte dei dispositivi, il servizio di recinto virtuale utilizza solo la posizione della rete per il recinto virtuale. attiva. Il servizio utilizza questo approccio perché la posizione di rete consuma molto meno dell'alimentazione, richiede meno tempo e, soprattutto, è disponibile in ambienti discreti.
Il Wi-Fi sia disattivato sul dispositivo. Avere il Wi-Fi attivo può migliorare notevolmente la precisione della geolocalizzazione; pertanto se il Wi-Fi non è attivo, la tua applicazione potrebbe non ricevere mai avvisi relativi al recinto virtuale a seconda di diverse impostazioni, tra cui il raggio del recinto virtuale, il modello del dispositivo o Versione di Android. A partire da Android 4.3 (livello API 18), abbiamo aggiunto la funzionalità "Ricerca di reti Wi-Fi" modalità Solo"" che consente agli utenti di disattivare il Wi-Fi, ma comunque di ottenere una buona posizione della rete. Buono esercitati a chiedere all'utente e a fornire una scorciatoia per attivare solo la ricerca di reti Wi-Fi o Wi-Fi se entrambe sono disabilitate. Utilizza SettingsClient per assicurarsi che le impostazioni di sistema del dispositivo siano configurate correttamente per il funzionamento ottimale. rilevamento della posizione.
Nota : se la tua app ha come target Android 10 (livello API 29) o maggiore, non puoi chiamare direttamente
WifiManager.setEnabled()
a meno che la tua app è un'app di sistema o un criterio relativo ai dispositivi un controller di deployment (DPC). Utilizza invece un riquadro delle impostazioni.- Non è disponibile una connettività di rete affidabile all'interno del recinto virtuale. Se c'è connessione dati non affidabile, è possibile che non vengano generati avvisi. Questo perché il servizio di recinto virtuale dipende dal fornitore di servizi di localizzazione della rete, che a sua volta richiede una connessione dati.
- Gli avvisi possono arrivare in ritardo. Il servizio del recinto virtuale non esegue query continue posizione geografica, quindi è prevista una certa latenza quando si riceve gli avvisi. Di solito la latenza è inferiore a 2 minuti, ancora meno quando il dispositivo è in movimento. Se Premessa I limiti di località sono attivi e la latenza è in media di circa 2-3 minuti. Se il dispositivo è stato fermo per un lungo periodo di tempo, la latenza potrebbe aumentare (fino a 6 minuti).
Risorse aggiuntive
Per scoprire di più sul geofencing, consulta il seguente materiale:
Campioni
App di esempio per la creazione e il monitoraggio di recinti virtuali.