Geofences erstellen und überwachen

Beim Geofencing wird die Kenntnis des aktuellen Standorts des Nutzers mit der Erkennung der Nähe des Nutzers zu interessanten Orten kombiniert. 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 Umkreis hinzu. Mit Breiten-, Längengrad und Radius wird ein Geofence definiert. Dabei wird ein kreisförmiger Bereich um den betreffenden Ort herum erstellt.

Sie können mehrere aktive Geofences haben. Pro App und Gerätenutzer sind maximal 100 Geofences möglich. Für jeden Geofence können Sie die Standortdienste bitten, Ihnen Ein- und Ausstiegsereignisse zu senden, oder Sie können eine Dauer innerhalb des Geofence-Bereichs angeben, die gewartet werden soll (Verweildauer), bevor ein Ereignis ausgelöst wird. Sie können die Dauer eines Geofence begrenzen, indem Sie eine Ablaufdauer in Millisekunden angeben. Nach Ablauf des Geofence wird er von den Ortungsdiensten automatisch entfernt.

In dieser Lektion erfahren Sie, wie Sie Geofences hinzufügen und entfernen und anschließend mit BroadcastReceiver auf Geofence-Übergänge warten.

Geofence-Monitoring einrichten

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

Weitere Informationen findest du in der Anleitung zum Anfordern von Berechtigungen zur Standortermittlung.

Wenn Sie ein BroadcastReceiver verwenden möchten, um Geofence-Übergänge zu beobachten, fügen Sie ein Element hinzu, das den Dienstnamen angibt. Dieses Element muss dem Element <application> untergeordnet sein:

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

Um auf die Standort-APIs zugreifen zu können, müssen Sie eine Instanz des Geofencing-Clients erstellen. So stellen Sie eine Verbindung zu Ihrem Kunden her:

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 von Geofences erstellen und hinzufügen. Um die Intents zu verarbeiten, die von den Standortdiensten bei Geofence-Übergängen gesendet werden, kannst du ein PendingIntent definieren, wie in diesem Abschnitt gezeigt.

Hinweis:Auf Einzelnutzergeräten gilt ein Limit von 100 Geofences pro App. Bei Geräten mit mehreren Nutzern liegt das Limit bei 100 Geofences pro App und Gerätenutzer.

Geofence-Objekte erstellen

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

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önnten Apps dynamisch Geofences erstellen, die auf dem Standort des Nutzers basieren.

Geofences und anfängliche Trigger angeben

Im folgenden Snippet werden die Klasse GeofencingRequest 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 fällt, und der Übergang GEOFENCE_TRANSITION_EXIT, wenn ein Gerät einen Geofence verlässt. Durch die Angabe von INITIAL_TRIGGER_ENTER wird für die Standortdienste festgelegt, dass GEOFENCE_TRANSITION_ENTER ausgelöst werden soll, wenn sich das Gerät bereits innerhalb des Geofence befindet.

In vielen Fällen ist die Verwendung von INITIAL_TRIGGER_DWELL besser geeignet, um Ereignisse nur dann auszulösen, wenn der Nutzer für eine festgelegte Dauer innerhalb eines Geofence anhält. Dieser Ansatz kann dazu beitragen, „Spambenachrichtigungen“ zu reduzieren, die durch eine große Anzahl von Benachrichtigungen entstehen, wenn ein Gerät kurz in Geofences eintritt oder diesen verlässt. Eine weitere Strategie für optimale Ergebnisse aus Ihren Geofences besteht darin, einen Mindestradius von 100 Metern festzulegen. Dadurch wird die Standortgenauigkeit typischer WLANs berücksichtigt und der Stromverbrauch des Geräts reduziert.

Einen Broadcast-Empfänger für Geofence-Übergänge definieren

Ein Intent, das von den Standortdiensten gesendet wird, kann verschiedene Aktionen in deiner App auslösen. Du solltest jedoch nicht zulassen, dass es eine Aktivität oder ein Fragment startet, da Komponenten nur 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 erhält Updates, wenn ein Ereignis eintritt, z. B. ein Übergang in einen oder aus einem Geofence, und kann lang andauernde Hintergrundarbeiten beginnen.

Das folgende Snippet zeigt, wie ein PendingIntent definiert wird, das einen 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 das Objekt 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, sendet er die Intent in der PendingIntent, die Sie in der Anfrage zum Hinzufügen von Geofences angegeben haben. Ein Broadcast-Empfänger wie GeofenceBroadcastReceiver stellt fest, dass Intent aufgerufen wurde, und kann dann das Geofencing-Ereignis vom Intent abrufen, den Typ der Geofence-Übergänge bestimmen und ermitteln, welche der definierten Geofences ausgelöst wurden. Der Broadcast-Empfänger kann eine App anweisen, im Hintergrund zu arbeiten, oder gegebenenfalls eine Benachrichtigung als Ausgabe zu senden.

Hinweis:Unter Android 8.0 (API-Level 26) und höher reagiert das Gerät alle paar Minuten auf Geofencing-Ereignisse, wenn eine App im Hintergrund ausgeführt wird, während ein Geofence überwacht wird. Informationen zum Anpassen Ihrer App an diese Antwortlimits finden Sie unter Limits für die Standortermittlung im Hintergrund.

Das folgende Snippet zeigt, wie ein BroadcastReceiver definiert wird, das eine Benachrichtigung sendet, wenn ein Geofence-Übergang erfolgt. 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 das BroadcastReceiver den Geofence-Übergangstyp ab und testet, ob dies eines der Ereignisse ist, das die App zum Auslösen von Benachrichtigungen verwendet – in diesem Fall entweder GEOFENCE_TRANSITION_ENTER oder GEOFENCE_TRANSITION_EXIT. Der Dienst sendet dann eine Benachrichtigung und protokolliert die Übergangsdetails.

Geofence-Monitoring beenden

Wenn Sie das Geofencing-Monitoring beenden, wenn es nicht mehr benötigt oder erwünscht ist, können Sie den Akku und die CPU-Zyklen des Geräts entlasten. Sie können das Geofencing-Monitoring in der Hauptaktivität beenden, die zum Hinzufügen und Entfernen von Geofences verwendet wird. Durch das Entfernen eines Geofences wird es sofort gestoppt. Die API bietet Methoden zum Entfernen von Geofences entweder über Anfrage-IDs oder durch Entfernen von Geofences, die mit einem bestimmten PendingIntent verknüpft sind.

Mit dem folgenden Snippet werden Geofences nach PendingIntent entfernt. Alle weiteren Benachrichtigungen werden gestoppt, wenn das Gerät zuvor hinzugefügte Geofences betritt 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 finden Sie in den anderen Lektionen dieses Kurses.

Best Practices für Geofencing

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

Stromverbrauch reduzieren

Mit den folgenden Methoden können Sie den Stromverbrauch in Apps optimieren, in denen Geofencing eingesetzt wird:

  • Legen Sie für die Reaktionsfähigkeit von Benachrichtigungen einen höheren Wert fest. Dies verbessert den Stromverbrauch, indem die Latenz von Geofence-Benachrichtigungen erhöht wird. Wenn Sie beispielsweise einen Wert für die Reaktionsfähigkeit von fünf Minuten festlegen, prüft Ihre App nur alle fünf Minuten eine Ein- oder Ausstiegsmeldung. Niedrigere Werte bedeuten nicht unbedingt, dass die Nutzer innerhalb dieses Zeitraums benachrichtigt werden. Wenn Sie beispielsweise einen Wert von 5 Sekunden festlegen, kann es etwas länger dauern, bis die Benachrichtigung eingeht.

  • Verwenden Sie einen größeren Geofence-Radius für Orte, an denen ein Nutzer viel Zeit verbringt, z. B. zu Hause oder am Arbeitsplatz. Ein größerer Radius reduziert zwar den Stromverbrauch nicht direkt, reduziert jedoch die Häufigkeit, mit der die Anwendung den Ein- oder Ausgang prüft, wodurch der gesamte Stromverbrauch reduziert wird.

Den optimalen Radius für Ihren Geofence auswählen

Für optimale Ergebnisse sollte der Mindestradius des Geofence zwischen 100 und 150 Metern liegen. Wenn WLAN verfügbar ist, liegt die Standortgenauigkeit in der Regel zwischen 20 und 50 Metern. Wenn ein Standort in Gebäuden verfügbar ist, kann der Genauigkeitsbereich bis zu 5 Meter betragen. Sofern Sie nicht wissen, dass innerhalb des Geofence ein Standort in Gebäuden verfügbar ist, gehen Sie von einer Standortgenauigkeit von etwa 50 Metern aus.

Wenn die WLAN-Standortermittlung nicht verfügbar ist, z. B. wenn Sie in ländlichen Gegenden fahren, wird die Standortgenauigkeit verschlechtert. Der Genauigkeitsbereich kann mehrere hundert Meter bis mehrere Kilometer betragen. In solchen Fällen sollten Sie Geofences mit einem größeren Radius erstellen.

Nutzern erklären, warum Ihre App Geofencing verwendet

Da Ihre App bei Verwendung von Geofencing im Hintergrund auf die Standortermittlung zugreift, sollten Sie überlegen, welche Vorteile Ihre App für die Nutzer bietet. Erläutere klar, warum deine App diesen Zugriff benötigt, um das Verständnis und die Transparenz der Nutzer zu verbessern.

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

Verweildauertyp verwenden, um Spam in Benachrichtigungen zu reduzieren

Wenn Sie eine große Anzahl von Benachrichtigungen erhalten, wenn Sie kurz über einen Geofence fahren, sollten Sie den Übergangstyp GEOFENCE_TRANSITION_DWELL anstelle von GEOFENCE_TRANSITION_ENTER verwenden, um die Anzahl der Benachrichtigungen zu reduzieren. Auf diese Weise wird die Verweildauer nur dann gesendet, wenn der Nutzer für einen bestimmten Zeitraum in einem Geofence 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 com.google.process.location-Prozess des Pakets com.google.android.gms gespeichert. Die App muss zur Verarbeitung der folgenden Ereignisse nichts tun, da das System Geofences nach diesen Ereignissen wiederherstellt:

  • Die Google Play-Dienste werden aktualisiert.
  • Google Play-Dienste werden vom System aufgrund von Ressourcenbeschränkungen beendet und neu gestartet.
  • Die Standortermittlung stürzt ab.

Die App 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 Aktion für den Abschluss des Bootvorgangs des Geräts warten und dann die erforderlichen Geofences noch einmal registrieren.
  • Die App wird deinstalliert und neu installiert.
  • Die Daten der App werden gelöscht.
  • Daten der Google Play-Dienste werden gelöscht.
  • Die App hat die Benachrichtigung GEOFENCE_NOT_AVAILABLE erhalten. Dies geschieht in der Regel, nachdem NLP (Network Location Provider, Android-Netzwerkanbieter) deaktiviert wurde.

Fehler beim Geofence-Eingangsereignis beheben

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

Hier sind einige mögliche Gründe dafür, dass Benachrichtigungen nicht wie erwartet funktionieren:

  • 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, um Geofence auszulösen. Der Dienst verwendet diesen Ansatz, da der Netzwerkstandort viel weniger Strom verbraucht, weniger Zeit für das Abrufen einzelner Standorte benötigt und vor allem in Innenräumen verfügbar ist.
  • WLAN auf dem Gerät ist deaktiviert. Bei aktiviertem WLAN kann die Standortgenauigkeit erheblich verbessert werden. Wenn WLAN deaktiviert ist, erhält Ihre App möglicherweise nie Geofence-Benachrichtigungen. Dies hängt von verschiedenen Einstellungen ab, z. B. vom Radius des Geofence, vom Gerätemodell oder von der Android-Version. Ab Android 4.3 (API-Level 18) haben wir die Möglichkeit des „Nur WLAN-Scanmodus“ hinzugefügt, mit dem Nutzer das WLAN deaktivieren und trotzdem eine gute Netzwerkverbindung erhalten können. Es empfiehlt sich, den Nutzer aufzufordern und ihm eine Tastenkombination anzubieten, mit der er den WLAN- oder den 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 deine App auf Android 10 (API-Level 29) oder höher ausgerichtet ist, kannst du WifiManager.setEnabled() nur dann direkt aufrufen, wenn deine App eine System-App oder ein Device Policy Controller (DPC) ist. Verwenden Sie stattdessen Einstellungen.

  • Innerhalb Ihres Geofence gibt es keine zuverlässige Netzwerkverbindung. Wenn keine zuverlässige Datenverbindung vorhanden ist, werden möglicherweise keine Benachrichtigungen generiert. Dies liegt daran, dass der Geofence-Dienst vom Netzwerkstandortanbieter abhängt, der wiederum eine Datenverbindung benötigt.
  • Benachrichtigungen können auch zu spät eingehen. Der Geofence-Dienst fragt nicht kontinuierlich den Standort ab. Daher sollten Sie beim Empfang von Benachrichtigungen mit einer gewissen Latenz rechnen. Normalerweise beträgt die Latenz weniger als 2 Minuten, sogar weniger, wenn das Gerät in Bewegung ist. Wenn Limits für die Standortermittlung im Hintergrund gelten, beträgt die Latenz im Durchschnitt 2 bis 3 Minuten. Wenn das Gerät längere Zeit nicht bewegt wurde, kann sich die Latenz erhöhen (bis zu 6 Minuten).

Weitere Informationen

Weitere Informationen zum Geofencing finden Sie in den folgenden Materialien:

Produktproben

Beispiel-App zum Erstellen und Überwachen von Geofences