Geofences erstellen und überwachen

Bei Geofencing wird der aktuelle Standort des Nutzers mit der Nähe zu Orten kombiniert, die von Interesse sein könnten. Wenn Sie einen interessanten Ort markieren möchten, geben Sie dessen Breiten- und Längengrad an. Wenn Sie die Entfernung für den Standort anpassen möchten, fügen Sie einen Radius hinzu. Breiten-, Längengrad und Radius definieren einen Geofence, d. h., um den betreffenden Ort wird eine kreisförmige Fläche oder ein Zaun definiert.

Sie können mehrere aktive Geofences mit maximal 100 Geofences pro App und Gerätenutzer haben. Sie können für jeden Geofence die Standortdienste bitten, Ihnen Eingangs- und Ausstiegsereignisse zu senden. Sie können aber auch eine Wartezeit oder Verweildauer innerhalb des Geofence-Bereichs angeben, bevor ein Ereignis ausgelöst wird. Sie können die Dauer eines Geofence begrenzen, indem Sie eine Ablaufzeit in Millisekunden angeben. Danach wird er von den Standortdiensten automatisch entfernt.

In dieser Lektion erfahren Sie, wie Sie Geofences hinzufügen und entfernen und dann mithilfe von BroadcastReceiver auf Geofence-Übergänge warten.

Für Geofence-Monitoring einrichten

Der erste Schritt beim Anfordern von Geofencing-Monitoring besteht darin, die erforderlichen Berechtigungen anzufordern. Damit Sie Geofencing verwenden können, muss Ihre App Folgendes anfordern:

Weitere Informationen finden Sie in der Anleitung zum Anfordern von Berechtigungen zur Standortermittlung.

Wenn Sie einen BroadcastReceiver verwenden möchten, um Geofence-Übergänge zu überwachen, fügen Sie ein Element hinzu, in dem der Dienstname angegeben ist. Dieses Element muss dem Element <application> untergeordnet sein:

<application
   android:allowBackup="true">
   ...
   <receiver android:name=".GeofenceBroadcastReceiver"/>
<application/>

Für den Zugriff auf die Standort-APIs müssen Sie eine Instanz des Geofencing-Clients erstellen. So verbinden Sie Ihren 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);
}

Geofences erstellen und hinzufügen

Ihre App muss Geofences mithilfe der Builder-Klasse der Location API zum Erstellen von Geofence-Objekten und der Convenience-Klasse zum Hinzufügen dieser Objekte erstellen und hinzufügen. Außerdem kannst du einen PendingIntent definieren, wie in diesem Abschnitt beschrieben, um die von Standortdiensten gesendeten Intents zu verarbeiten, wenn Geofence-Übergänge auftreten.

Hinweis:Auf Geräten mit Einzelnutzern gilt ein Limit von 100 Geofences pro App. Bei Geräten mit mehreren Nutzern beträgt das Limit 100 Geofences pro App und Gerätenutzer.

Geofence-Objekte erstellen

Erstellen Sie zuerst mit Geofence.Builder einen Geofence und legen Sie den gewünschten Radius, die Dauer und die Übergangstypen für den Geofence fest. So füllen Sie beispielsweise ein Listenobjekt:

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());

In diesem Beispiel werden Daten aus einer Konstantendatei abgerufen. In der Praxis können Anwendungen Geofences basierend auf dem Standort des Nutzers dynamisch erstellen.

Geofences und anfängliche Trigger angeben

Im folgenden Snippet werden die GeofencingRequest-Klasse und ihre verschachtelte GeofencingRequestBuilder-Klasse verwendet, um die zu überwachenden Geofences anzugeben und festzulegen, wie verwandte Geofence-Ereignisse ausgelöst werden:

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();
}

Dieses Beispiel zeigt die Verwendung von zwei Geofence-Triggern. Der Übergang GEOFENCE_TRANSITION_ENTER wird ausgelöst, wenn ein Gerät in einen Geofence übergeht, und der Übergang GEOFENCE_TRANSITION_EXIT wird ausgelöst, wenn ein Gerät einen Geofence verlässt. Wenn Sie INITIAL_TRIGGER_ENTER angeben, wird den Standortdiensten mitgeteilt, dass GEOFENCE_TRANSITION_ENTER ausgelöst werden soll, wenn sich das Gerät bereits innerhalb des Geofence befindet.

In vielen Fällen empfiehlt es sich, stattdessen INITIAL_TRIGGER_DWELL zu verwenden. Damit werden Ereignisse nur dann ausgelöst, wenn der Nutzer innerhalb eines Geofence für eine bestimmte Dauer anhält. Mit diesem Ansatz können Sie „Benachrichtigungs-Spam“ reduzieren, der bei einer großen Anzahl von Benachrichtigungen entsteht, wenn ein Gerät einen Geofences kurzzeitig erreicht und verlässt. Eine weitere Strategie für optimale Ergebnisse aus Ihren Geofences besteht darin, einen Mindestradius von 100 Metern festzulegen. Dies trägt dazu bei, die Standortgenauigkeit typischer WLAN-Netzwerke zu berücksichtigen und den Stromverbrauch der Geräte zu senken.

Übertragungsempfänger für Geofence-Übergänge definieren

Eine von Standortdiensten gesendete Intent kann verschiedene Aktionen in deiner App auslösen. Du solltest jedoch keine Aktivität oder Fragmentierung starten, da die Komponenten erst als Reaktion auf eine Nutzeraktion sichtbar werden sollen. In vielen Fällen ist ein BroadcastReceiver eine gute Möglichkeit, einen Geofence-Übergang zu verarbeiten. Ein BroadcastReceiver wird aktualisiert, wenn ein Ereignis eintritt, z. B. ein Wechsel in einen oder aus einem Geofence, und kann mit lang andauernden Hintergrundarbeiten beginnen.

Das folgende Snippet zeigt, wie ein PendingIntent definiert wird, das ein BroadcastReceiver startet:

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;
    }

Geofences hinzufügen

Verwenden Sie die Methode GeofencingClient.addGeofences(), um Geofences hinzuzufügen. Geben Sie die Objekte GeofencingRequest und PendingIntent an. Das folgende Snippet veranschaulicht die Verarbeitung der Ergebnisse:

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
                // ...
            }
        });

Geofence-Übergänge verarbeiten

Wenn die Standortdienste erkennen, dass der Nutzer einen Geofence betreten oder verlassen hat, werden die Intent in der PendingIntent gesendet, die du in der Anfrage zum Hinzufügen von Geofences angegeben hast. Ein Übertragungsempfänger wie GeofenceBroadcastReceiver erkennt, dass Intent aufgerufen wurde, und kann dann das Geofencing-Ereignis vom Intent abrufen, die Art der Geofence-Übergänge bestimmen und bestimmen, welcher der definierten Geofences ausgelöst wurde. Der Übertragungsempfänger kann eine App anweisen, im Hintergrund Aufgaben auszuführen, oder bei Bedarf eine Benachrichtigung als Ausgabe zu senden.

Hinweis:Wenn unter Android 8.0 (API-Level 26) und höher eine App im Hintergrund ausgeführt wird, während ein Geofence überwacht wird, reagiert das Gerät alle paar Minuten auf Geofencing-Ereignisse. Informationen dazu, wie du deine App an diese Antwortlimits anpassen kannst, findest du unter Limits für die Standortermittlung im Hintergrund.

Das folgende Snippet zeigt, wie ein BroadcastReceiver definiert wird, mit dem bei einem Geofence-Übergang eine Benachrichtigung gesendet wird. Wenn der Nutzer auf die Benachrichtigung klickt, wird die Hauptaktivität der App angezeigt:

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));
        }
    }
}

Nachdem das Übergangsereignis über PendingIntent erkannt wurde, ruft BroadcastReceiver den Geofence-Übergangstyp ab und testet, ob es sich um eines der Ereignisse handelt, die die Anwendung zum Auslösen von Benachrichtigungen verwendet – in diesem Fall GEOFENCE_TRANSITION_ENTER oder GEOFENCE_TRANSITION_EXIT. Der Dienst sendet dann eine Benachrichtigung und protokolliert die Details zur Umstellung.

Geofence-Monitoring beenden

Das Beenden des Geofence-Monitorings, wenn es nicht mehr benötigt oder erwünscht ist, kann dazu beitragen, die Akkuleistung und CPU-Zyklen des Geräts zu schonen. Sie können das Geofence-Monitoring in der Hauptaktivität beenden, mit der Geofences hinzugefügt und entfernt werden. Durch das Entfernen eines Geofence wird es sofort gestoppt. Die API bietet Methoden zum Entfernen von Geofences entweder über Anfrage-IDs oder durch Entfernen von Geofences, die mit einer bestimmten PendingIntent verknüpft sind.

Mit dem folgenden Snippet werden Geofences nach PendingIntent entfernt. Dadurch werden alle weiteren Benachrichtigungen gestoppt, wenn das Gerät zuvor hinzugefügte Geofences erreicht oder verlässt:

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
                // ...
            }
        });

Sie können Geofencing mit anderen standortbezogenen Funktionen kombinieren, z. B. mit regelmäßigen Standortupdates. Weitere Informationen findest du in den anderen Lektionen dieses Kurses.

Best Practices für Geofencing

In diesem Abschnitt finden Sie Empfehlungen zur Verwendung von Geofencing mit den Standort-APIs für Android.

Stromverbrauch reduzieren

Mit den folgenden Methoden können Sie den Stromverbrauch in Apps mit Geofencing optimieren:

  • Legen Sie einen höheren Wert für die Benachrichtigungsreaktionsfähigkeit fest. Dadurch wird der Stromverbrauch optimiert, da die Latenz von Geofence-Benachrichtigungen erhöht wird. Wenn Sie beispielsweise einen Wert für die Reaktionsfähigkeit von fünf Minuten festlegen, sucht Ihre App nur alle fünf Minuten auf eine Ein- oder Ausfahrt. Niedrigere Werte bedeuten nicht unbedingt, dass Nutzer innerhalb dieses Zeitraums benachrichtigt werden. Wenn Sie beispielsweise einen Wert von 5 Sekunden festlegen, kann es etwas länger dauern, bis die Benachrichtigung empfangen wird.

  • Verwenden Sie einen größeren Geofence-Radius für Standorte, an denen ein Nutzer viel Zeit verbringt, z. B. Ihr Zuhause oder Ihre Arbeit. Ein größerer Radius reduziert zwar den Stromverbrauch nicht direkt, verringert aber die Häufigkeit, mit der die Anwendung den Ein- oder Ausgang prüft, wodurch der Gesamtstromverbrauch effektiv reduziert wird.

Optimalen Radius für Ihren Geofence auswählen

Die besten Ergebnisse erzielen Sie, wenn der Mindestradius des Geofence zwischen 100 und 150 Metern liegt. Wenn WLAN verfügbar ist, liegt die Standortgenauigkeit in der Regel zwischen 20 und 50 Metern. Wenn Indoor-Karten verfügbar sind, kann der Bereich auf bis zu 5 Meter genau sein. Wenn Sie nicht wissen, dass Standorte innerhalb des Geofence verfügbar sind, wird davon ausgegangen, dass die WLAN-Standortgenauigkeit etwa 50 Meter beträgt.

Wenn kein WLAN-Standort verfügbar ist, z. B. beim Autofahren in ländlichen Gebieten, verschlechtert sich die Standortgenauigkeit. Der Genauigkeitsbereich kann zwischen mehreren hundert Metern und mehreren Kilometern liegen. In solchen Fällen sollten Sie Geofences mit einem größeren Radius erstellen.

Nutzern erklären, warum in Ihrer App Geofencing verwendet wird

Da Ihre App bei Verwendung von Geofencing im Hintergrund auf die Standortermittlung zugreift, sollten Sie sich überlegen, welche Vorteile sie Nutzern bietet. Erkläre ihnen klar, warum deine App diesen Zugriff benötigt, um für mehr Verständnis und Transparenz zu sorgen.

Weitere Informationen zu Best Practices für den Standortzugriff, einschließlich Geofencing, finden Sie auf der Seite Best Practices zum Datenschutz.

Verwenden Sie den Übergangstyp für die Verweildauer, um Warnmeldungen-Spam zu reduzieren

Wenn Sie eine große Anzahl von Benachrichtigungen erhalten, wenn Sie kurz an einem Geofence vorbeifahren, verwenden Sie am besten den Übergangstyp GEOFENCE_TRANSITION_DWELL anstelle von GEOFENCE_TRANSITION_ENTER, um die Benachrichtigungen zu reduzieren. Auf diese Weise wird die Verweildauer-Benachrichtigung nur gesendet, wenn der Nutzer in einem Geofence für einen bestimmten Zeitraum anhält. Sie können die Dauer durch Festlegen einer Verzögerungsverzögerung auswählen.

Geofences nur bei Bedarf neu registrieren

Registrierte Geofences werden im Prozess com.google.process.location beibehalten, der zum Paket com.google.android.gms gehört. Die Anwendung muss nichts tun, um die folgenden Ereignisse zu verarbeiten, da das System Geofences nach diesen Ereignissen wiederhergestellt:

  • Die Google Play-Dienste wurden aktualisiert.
  • Google Play-Dienste werden aufgrund von Ressourceneinschränkungen vom System beendet und neu gestartet.
  • Der Standortprozess stürzt ab.

Die Anwendung muss Geofences noch einmal registrieren, wenn sie nach den folgenden Ereignissen noch benötigt werden, da das System die Geofences in den folgenden Fällen nicht wiederherstellen kann:

  • Das Gerät wird neu gestartet. Die App sollte auf die abgeschlossene Bootaktion des Geräts warten und dann die erforderlichen Geofences noch einmal registrieren.
  • Die App wird deinstalliert und neu installiert.
  • Die App-Daten werden gelöscht.
  • Die Daten der Google Play-Dienste werden gelöscht.
  • Die Anwendung hat die Benachrichtigung GEOFENCE_NOT_AVAILABLE erhalten. Das passiert in der Regel, nachdem NLP (Network Location Provider, Android-Netzwerkstandortanbieter) deaktiviert ist.

Fehler beim Geofence-Einstiegsereignis beheben

Wenn keine Geofences ausgelöst werden, wenn das Gerät in einen Geofence eintritt (die GEOFENCE_TRANSITION_ENTER-Benachrichtigung wird nicht ausgelöst), prüfen Sie zuerst, ob Ihre Geofences ordnungsgemäß registriert sind, wie in diesem Leitfaden beschrieben.

Wenn Benachrichtigungen nicht wie erwartet funktionieren, kann das folgende Gründe haben:

  • Der genaue Standort ist innerhalb Ihres Geofence nicht verfügbar oder Ihr Geofence ist zu klein. Auf den meisten Geräten verwendet der Geofence-Dienst nur den Netzwerkstandort zum Auslösen von Geofence. Der Dienst verwendet diesen Ansatz, da der Netzwerkstandort viel weniger Strom verbraucht, weniger Zeit benötigt, um diskrete Standorte zu finden, und vor allem, dass er in Innenräumen verfügbar ist.
  • WLAN ist auf dem Gerät deaktiviert. Durch die Aktivierung von WLAN kann die Standortgenauigkeit erheblich verbessert werden. Wenn WLAN deaktiviert ist, erhält Ihre App je nach verschiedenen Einstellungen wie dem Radius des Geofence, des Gerätemodells oder der Android-Version möglicherweise keine Geofence-Benachrichtigungen. Ab Android 4.3 (API-Level 18) haben wir den „Nur WLAN-Scanmodus“-Modus hinzugefügt, mit dem Nutzer das WLAN deaktivieren können, aber trotzdem einen guten Netzwerkstandort erhalten. Es hat sich bewährt, den Nutzer aufzufordern und ihm eine Verknüpfung zu geben, mit der er den WLAN- oder WLAN-Scanmodus aktivieren kann, wenn beide deaktiviert sind. Mit SettingsClient sorgen Sie dafür, dass die Systemeinstellungen des Geräts für eine optimale Standorterkennung richtig konfiguriert sind.

    Hinweis : Wenn Ihre App auf Android 10 (API-Level 29) oder höher ausgerichtet ist, können Sie WifiManager.setEnabled() nur dann direkt aufrufen, wenn Ihre App eine System-App oder ein Device Policy Controller (DPC) ist. Verwenden Sie stattdessen einen Einstellungsbereich.

  • Innerhalb Ihres Geofence gibt es keine zuverlässige Netzwerkverbindung. Wenn keine zuverlässige Datenverbindung besteht, werden möglicherweise keine Benachrichtigungen generiert. Das liegt daran, dass der Geofencing-Dienst vom Netzwerkstandortanbieter abhängt, der wiederum eine Datenverbindung erfordert.
  • Benachrichtigungen können sich verspäten. Der Geofence-Dienst fragt den Standort nicht kontinuierlich ab. Daher ist beim Empfang von Benachrichtigungen eine gewisse Latenz zu erwarten. In der Regel beträgt die Latenz weniger als 2 Minuten, noch geringer, wenn das Gerät in Bewegung ist. Wenn Limits für die Standortermittlung im Hintergrund aktiviert sind, beträgt die Latenz im Durchschnitt etwa 2 bis 3 Minuten. Wenn das Gerät längere Zeit nicht aktiv war, kann sich die Latenz erhöhen (bis zu 6 Minuten).

Zusätzliche Ressourcen

Weitere Informationen zu Geofencing finden Sie in den folgenden Materialien:

Produktproben

Beispielanwendung zum Erstellen und Überwachen von Geofences