Geofencing łączy informacje o bieżącej lokalizacji użytkownika z informacjami o jego bliskości do miejsc, które mogą go zainteresować. Aby oznaczyć lokalizację interesującą użytkownika, podaj jej szerokość i długość geograficzną. Aby dostosować bliskość lokalizacji, dodaj obszar o określonym promieniu. Szerokość i długość geograficzna oraz promień definiują geofence, tworząc okrągły obszar lub ogrodzenie wokół lokalizacji interesującej użytkownika.
Możesz mieć wiele aktywnych geofence, z limitem 100 na aplikację na użytkownika urządzenia. W przypadku każdego obszaru geofence możesz poprosić usługi lokalizacyjne o wysyłanie zdarzeń wejścia i wyjścia lub określić czas oczekiwania (przebywania) w obszarze geofence przed wywołaniem zdarzenia. Możesz ograniczyć czas trwania dowolnego geofence, określając czas ważności w milisekundach. Po wygaśnięciu geofence usługi lokalizacyjne automatycznie go usuwają.
Z tej lekcji dowiesz się, jak dodawać i usuwać geofence, a następnie nasłuchiwać przejść między nimi za pomocą BroadcastReceiver.
Uwaga: na urządzeniach Wear interfejsy API geofencingu nie wykorzystują efektywnie energii. Nie zalecamy używania tych interfejsów API na Wear. Więcej informacji znajdziesz w artykule Oszczędzanie energii i baterii.
Konfigurowanie monitorowania geofence
Pierwszym krokiem w celu wysłania prośby o monitorowanie geofence jest poproszenie o niezbędne uprawnienia. Aby korzystać z geofencingu, aplikacja musi prosić o te uprawnienia:
-
ACCESS_FINE_LOCATION -
ACCESS_BACKGROUND_LOCATIONjeśli aplikacja jest kierowana na Androida 10 (API na poziomie 29) lub nowszego;
Więcej informacji znajdziesz w przewodniku na temat wysyłania próśb o dostęp do lokalizacji.
Jeśli chcesz używać BroadcastReceiver do nasłuchiwania przejść przez geofence, dodaj element określający nazwę usługi. Ten element musi być elementem podrzędnym elementu
<application>:
<application android:allowBackup="true"> ... <receiver android:name=".GeofenceBroadcastReceiver"/> <application/>
Aby uzyskać dostęp do interfejsów API lokalizacji, musisz utworzyć instancję klienta geofencingu. Aby dowiedzieć się, jak połączyć klienta:
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); }
Tworzenie i dodawanie geofence
Aplikacja musi tworzyć i dodawać geofence, używając klasy kreatora interfejsu API lokalizacji do tworzenia obiektów geofence oraz klasy pomocniczej do ich dodawania. Aby obsługiwać intencje wysyłane przez usługi lokalizacyjne, gdy dochodzi do przejść między geofence, możesz zdefiniować PendingIntent, jak pokazano w tej sekcji.
Uwaga: na urządzeniach z jednym użytkownikiem obowiązuje limit 100 geofence na aplikację. Na urządzeniach z wieloma użytkownikami limit wynosi 100 geofence na aplikację na użytkownika urządzenia.
Tworzenie obiektów geofence
Najpierw użyj
Geofence.Builder, aby utworzyć geofence, ustawiając żądany promień, czas trwania i typy przejść dla geofence. Aby na przykład wypełnić obiekt listy:
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());
W tym przykładzie dane są pobierane z pliku stałych. W praktyce aplikacje mogą dynamicznie tworzyć geofence na podstawie lokalizacji użytkownika.
Określanie geofence i początkowych aktywatorów
Ten fragment kodu używa klasy
GeofencingRequest i jej zagnieżdżonej klasy
GeofencingRequestBuilder do określenia geofence'ów, które mają być monitorowane, oraz do ustawienia sposobu wywoływania powiązanych zdarzeń geofence:
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(); }
Ten przykład pokazuje użycie 2 reguł geofence. Przejście
GEOFENCE_TRANSITION_ENTER jest aktywowane, gdy urządzenie wchodzi w obszar geofence, a przejście
GEOFENCE_TRANSITION_EXIT – gdy urządzenie opuszcza ten obszar. Określenie
INITIAL_TRIGGER_ENTER informuje usługi lokalizacyjne, że
GEOFENCE_TRANSITION_ENTER powinno zostać wywołane, jeśli urządzenie znajduje się już w geofence.
W wielu przypadkach lepiej jest używać interfejsu
INITIAL_TRIGGER_DWELL, który wywołuje zdarzenia tylko wtedy, gdy użytkownik zatrzyma się na określony czas w obrębie geofence.
Takie podejście może pomóc ograniczyć „spam alertami” wynikający z dużej liczby powiadomień, gdy urządzenie na krótko wchodzi w obszar geofence i go opuszcza. Inną strategią pozwalającą uzyskać najlepsze wyniki z geofence jest ustawienie minimalnego promienia na 100 metrów. Pomaga to uwzględnić dokładność lokalizacji typowych sieci Wi-Fi, a także zmniejszyć zużycie energii przez urządzenie.
Definiowanie odbiornika dla przejść między geofence
Intent wysłany z usług lokalizacyjnych może wywołać różne działania w aplikacji, ale nie powinien uruchamiać aktywności ani fragmentu, ponieważ komponenty powinny być widoczne tylko w odpowiedzi na działanie użytkownika. W wielu przypadkach BroadcastReceiver to dobry sposób na obsługę przejścia przez geofence. BroadcastReceiver otrzymuje aktualizacje, gdy wystąpi zdarzenie, takie jak wejście do geofence lub wyjście z niego, i może rozpocząć długotrwałe zadanie w tle.
Poniższy fragment kodu pokazuje, jak zdefiniować element PendingIntent, który uruchamia element BroadcastReceiver:
Kotlin
class MainActivity : AppCompatActivity() { // ... private val geofencePendingIntent: PendingIntent by lazy { // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling // addGeofences() and removeGeofences(). val flags = PendingIntent.FLAG_UPDATE_CURRENT if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { // Starting on Android S+ the pending intent has to be mutable. flags or PendingIntent.FLAG_MUTABLE } val intent = Intent(this, GeofenceBroadcastReceiver::class.java) PendingIntent.getBroadcast(this, 0, intent, flags) } }
Java
public class MainActivity extends AppCompatActivity { // ... private PendingIntent getGeofencePendingIntent() { // Reuse the PendingIntent if we already have it. if (geofencePendingIntent != null) { return geofencePendingIntent; } // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling // addGeofences() and removeGeofences(). int flags = PendingIntent.FLAG_UPDATE_CURRENT; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { // Starting on Android S+ the pending intent has to be mutable. flags |= PendingIntent.FLAG_MUTABLE; } Intent intent = new Intent(this, GeofenceBroadcastReceiver.class); geofencePendingIntent = PendingIntent.getBroadcast(this, 0, intent, flags); return geofencePendingIntent; } }
Dodawanie geofence
Aby dodać geofence, użyj metody
.
Podaj obiekt GeofencingClient.addGeofences()
GeofencingRequest i PendingIntent.
Poniższy fragment kodu pokazuje, jak przetwarzać wyniki:
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 // ... } });
Obsługa przejść między geofence
Gdy usługi lokalizacyjne wykryją, że użytkownik wszedł na obszar geofence lub go opuścił, wysyłają obiekt Intent zawarty w obiekcie PendingIntent, który został uwzględniony w żądaniu dodania obszarów geofence. Odbiornik, taki jak GeofenceBroadcastReceiver, zauważa, że wywołano Intent, i może uzyskać zdarzenie geofencingu z intencji, określić typ przejścia geofence i ustalić, który ze zdefiniowanych geofence został aktywowany. Odbiornik może nakazać aplikacji rozpoczęcie pracy w tle lub, jeśli jest to pożądane, wysłać powiadomienie jako dane wyjściowe.
Uwaga: na Androidzie 8.0 (interfejs API na poziomie 26) i nowszych wersjach, jeśli aplikacja działa w tle i monitoruje geofence, urządzenie reaguje na zdarzenia geofence co kilka minut. Aby dowiedzieć się, jak dostosować aplikację do tych limitów odpowiedzi, zapoznaj się z artykułem Ograniczenia dotyczące lokalizacji w tle.
Poniższy fragment kodu pokazuje, jak zdefiniować obiekt BroadcastReceiver, który wysyła powiadomienie, gdy nastąpi przejście przez geofence. Gdy użytkownik kliknie powiadomienie, pojawi się główna aktywność aplikacji:
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)); } } }
Po wykryciu zdarzenia przejścia przez PendingIntent BroadcastReceiver pobiera typ przejścia geofence i sprawdza, czy jest to jedno ze zdarzeń, których aplikacja używa do wywoływania powiadomień – w tym przypadku GEOFENCE_TRANSITION_ENTER lub GEOFENCE_TRANSITION_EXIT. Następnie usługa wysyła powiadomienie i rejestruje szczegóły przejścia.
Zatrzymywanie monitorowania geofence
Zatrzymanie monitorowania geofence, gdy nie jest już potrzebne, może pomóc oszczędzać baterię i cykle procesora na urządzeniu. Możesz zatrzymać monitorowanie geofence w głównej aktywności używanej do dodawania i usuwania geofence. Usunięcie geofence powoduje natychmiastowe zatrzymanie monitorowania. Interfejs API udostępnia metody usuwania geofence według identyfikatorów żądań lub przez usunięcie geofence powiązanych z danym obiektem PendingIntent.
Ten fragment kodu usuwa geofence według PendingIntent, co powoduje zatrzymanie wszystkich dalszych powiadomień, gdy urządzenie wejdzie na obszar wcześniej dodanych geofence lub go opuści:
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 // ... } });
Możesz połączyć geofencing z innymi funkcjami wykrywania lokalizacji, takimi jak okresowe informacje o zmianie lokalizacji. Więcej informacji znajdziesz w innych lekcjach z tego kursu.
Stosowanie sprawdzonych metod dotyczących geofencingu
W tej sekcji znajdziesz zalecenia dotyczące korzystania z geofencingu z interfejsami API lokalizacji na Androida.
Zmniejszanie zużycia energii
Aby zoptymalizować zużycie energii w aplikacjach korzystających z geofencingu, możesz użyć tych technik:
Ustaw wyższą wartość reakcji na powiadomienia. Zmniejsza to zużycie energii, ponieważ wydłuża czas oczekiwania na alerty geofence. Jeśli na przykład ustawisz czas reakcji na 5 minut, aplikacja będzie sprawdzać alerty o wejściu lub wyjściu tylko raz na 5 minut. Ustawienie niższych wartości nie musi oznaczać, że użytkownicy zostaną powiadomieni w tym czasie (np. jeśli ustawisz wartość 5 sekund, otrzymanie alertu może potrwać nieco dłużej).
Używaj większego promienia geofence w przypadku lokalizacji, w których użytkownik spędza dużo czasu, takich jak dom lub praca. Chociaż większy promień nie zmniejsza bezpośrednio zużycia energii, zmniejsza częstotliwość sprawdzania przez aplikację wejścia lub wyjścia, co skutecznie obniża ogólne zużycie energii.
Wybierz optymalny promień geofence.
Aby uzyskać najlepsze wyniki, minimalny promień geofence powinien wynosić 100–150 metrów. Gdy dostępna jest sieć Wi-Fi, dokładność lokalizacji wynosi zwykle 20–50 metrów. Gdy dostępna jest lokalizacja w budynku, zakres dokładności może wynosić nawet 5 metrów. Jeśli nie wiesz, czy w obrębie geofence jest dostępna lokalizacja w pomieszczeniach, załóż, że dokładność lokalizacji Wi-Fi wynosi około 50 metrów.
Gdy lokalizacja Wi-Fi jest niedostępna (np. podczas jazdy po obszarach wiejskich), dokładność lokalizacji spada. Zakres dokładności może wynosić od kilkuset metrów do kilku kilometrów. W takich przypadkach należy tworzyć geofence o większym promieniu.
Wyjaśnij użytkownikom, dlaczego Twoja aplikacja korzysta z geofencingu
Ponieważ aplikacja uzyskuje dostęp do lokalizacji w tle, gdy używasz geofencingu, zastanów się, jakie korzyści przynosi ona użytkownikom. Jasno wyjaśnij użytkownikom, dlaczego Twoja aplikacja potrzebuje tego dostępu, aby zwiększyć ich zrozumienie i przejrzystość.
Więcej informacji o sprawdzonych metodach związanych z dostępem do lokalizacji, w tym o geofencingu, znajdziesz na stronie ze sprawdzonymi metodami dotyczącymi prywatności.
Używanie typu przejścia „czas przebywania” w celu ograniczenia spamu związanego z alertami
Jeśli podczas krótkiej jazdy obok geofence otrzymujesz dużą liczbę alertów, najlepszym sposobem na ich ograniczenie jest użycie typu przejścia
GEOFENCE_TRANSITION_DWELL zamiast
GEOFENCE_TRANSITION_ENTER. Dzięki temu alert o przebywaniu w danym miejscu jest wysyłany tylko wtedy, gdy użytkownik zatrzyma się w geofence na określony czas. Możesz wybrać czas trwania, ustawiając
opóźnienie wykrywania.
Ponowna rejestracja geofence tylko wtedy, gdy jest to wymagane
Zarejestrowane geofence są przechowywane w procesie com.google.process.location należącym do pakietu com.google.android.gms.
Aplikacja nie musi nic robić, aby obsłużyć te zdarzenia, ponieważ system przywraca geofence po ich wystąpieniu:
- Usługi Google Play zostały uaktualnione.
- Usługi Google Play zostały zamknięte i ponownie uruchomione przez system z powodu ograniczenia zasobów.
- Proces lokalizacji ulega awarii.
Aplikacja musi ponownie zarejestrować geofence, jeśli są one nadal potrzebne po tych zdarzeniach, ponieważ system nie może ich odzyskać w tych przypadkach:
- Urządzenie zostanie ponownie uruchomione. Aplikacja powinna nasłuchiwać działania związanego z zakończeniem uruchamiania urządzenia, a następnie ponownie zarejestrować wymagane geofence.
- Aplikacja zostanie odinstalowana i ponownie zainstalowana.
- Dane aplikacji zostaną wyczyszczone.
- Dane usług Google Play zostaną wyczyszczone.
- Aplikacja otrzymała alert
GEOFENCE_NOT_AVAILABLE. Zwykle dzieje się tak po wyłączeniu NLP (dostawcy lokalizacji sieciowej Androida).
Rozwiązywanie problemów ze zdarzeniem wejścia do geofence
Jeśli geofence nie jest aktywowany, gdy urządzenie wchodzi w jego obszar (alert
GEOFENCE_TRANSITION_ENTER nie jest aktywowany), najpierw upewnij się, że geofence jest prawidłowo zarejestrowany, jak opisano w tym przewodniku.
Oto kilka możliwych przyczyn, dla których alerty nie działają zgodnie z oczekiwaniami:
- Dokładna lokalizacja jest niedostępna w obrębie geofence lub geofence jest zbyt mały. Na większości urządzeń usługa geofence używa tylko lokalizacji sieciowej do aktywowania geofence. Usługa korzysta z tego podejścia, ponieważ lokalizacja sieciowa zużywa znacznie mniej energii, uzyskanie dyskretnych lokalizacji zajmuje mniej czasu i co najważniejsze, jest ona dostępna w pomieszczeniach.
Wi-Fi jest wyłączone na urządzeniu. Włączenie Wi-Fi może znacznie poprawić dokładność lokalizacji, więc jeśli Wi-Fi jest wyłączone, aplikacja może nigdy nie otrzymywać alertów geofence w zależności od kilku ustawień, w tym promienia geofence, modelu urządzenia lub wersji Androida. Od Androida 4.3 (poziom interfejsu API 18) dodaliśmy funkcję „trybu skanowania tylko Wi-Fi”, która umożliwia użytkownikom wyłączenie Wi-Fi, ale nadal zapewnia dobrą lokalizację sieciową. Dobrą praktyką jest wyświetlenie użytkownikowi prośby i skrótu, aby mógł włączyć Wi-Fi lub tryb skanowania tylko Wi-Fi, jeśli obie te opcje są wyłączone. Użyj SettingsClient, aby upewnić się, że ustawienia systemowe urządzenia są prawidłowo skonfigurowane pod kątem optymalnego wykrywania lokalizacji.
Uwaga: jeśli Twoja aplikacja jest kierowana na Androida 10 (API na poziomie 29) lub nowszego, nie możesz bezpośrednio wywołać metody
WifiManager.setEnabled(), chyba że Twoja aplikacja jest aplikacją systemową lub kontrolerem zasad dotyczących urządzeń (DPC). Zamiast tego użyj panelu ustawień.- W obszarze geofence nie ma stabilnego połączenia sieciowego. Jeśli nie ma niezawodnego połączenia do transmisji danych, alerty mogą nie być generowane. Dzieje się tak, ponieważ usługa geofence zależy od dostawcy lokalizacji sieciowej, który z kolei wymaga połączenia do transmisji danych.
- Alerty mogą być opóźnione. Usługa geofence nie wysyła zapytań ciągłych o lokalizację, więc alerty mogą być odbierane z pewnym opóźnieniem. Zwykle opóźnienie wynosi mniej niż 2 minuty, a nawet mniej, gdy urządzenie się porusza. Jeśli obowiązują ograniczenia lokalizacji w tle, czas oczekiwania wynosi średnio około 2–3 minut. Jeśli urządzenie nie było używane przez dłuższy czas, czas oczekiwania może się wydłużyć (do 6 minut).
Dodatkowe materiały
Więcej informacji o geofencingu znajdziesz w tych materiałach:
Przykłady
Przykładowa aplikacja do tworzenia i monitorowania geofence.