Geofencing łączy informacje o obecnej lokalizacji użytkownika z informacjami o odległości od miejsc, które mogą go zainteresować. Aby oznaczyć interesującą lokalizację, podaj jej szerokość i długość geograficzną. Aby dostosować zbliżenie do lokalizacji, dodaj promień. Szerokość i długość geograficzna oraz promień określają geofence, tworząc obszar wokół interesującej Cię lokalizacji.
Możesz mieć wiele aktywnych geofence’ów, ale ich liczba nie może przekroczyć 100 na aplikację i na użytkownika urządzenia. W przypadku każdego geoogrodzenia możesz poprosić Usługi lokalizacyjne o wysyłanie zdarzeń wejścia i wyjścia lub określić czas oczekiwania (pobytu) w strefie geoogrodzenia przed wywołaniem zdarzenia. Możesz ograniczyć czas trwania dowolnej geofence, podając czas wygaśnięcia w milisekundach. Po upływie czasu, na który ustawiono geofence, usługi lokalizacyjne automatycznie ją usuwają.
Z tej lekcji dowiesz się, jak dodawać i usuwać geoogrodzenia oraz jak odbierać zdarzenia przejścia przez geoogrodzenia za pomocą BroadcastReceiver
.
Uwaga: na urządzeniach Wear interfejsy API geofence 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 prośbie o monitorowanie geoogrodzenia jest prośba o wymagane uprawnienia. Aby można było korzystać z geofencingu, aplikacja musi prosić o:
-
ACCESS_FINE_LOCATION
-
ACCESS_BACKGROUND_LOCATION
jeśli aplikacja jest kierowana na Androida 10 (poziom interfejsu API 29) lub nowszego
Więcej informacji znajdziesz w przewodniku Prośba o dostęp do lokalizacji.
Jeśli chcesz używać BroadcastReceiver
do słuchania przejść w geofencingu, 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’ów
Aplikacja musi tworzyć i dodawać geoogrodzenia za pomocą klasy konstruktora interfejsu API lokalizacji do tworzenia obiektów Geofence oraz klasy ułatwiającej ich dodawanie. Aby obsłużyć intencje wysyłane przez Usługi lokalizacyjne po przejściu przez geofence, możesz zdefiniować PendingIntent
, jak pokazano w tej sekcji.
Uwaga: na urządzeniach jednoużytkownikowych można ustawić maksymalnie 100 geofence’ów na aplikację. W przypadku urządzeń wieloużytkownikowych limit wynosi 100 geofence’ów na aplikację na każdego użytkownika.
Tworzenie obiektów geofence
Najpierw użyj
Geofence.Builder
, aby utworzyć geofence, ustawiając pożądany promień, czas trwania i typy przejść. 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 z wartościami stałymi. W praktyce aplikacje mogą dynamicznie tworzyć geoogrodzenia na podstawie lokalizacji użytkownika.
Określanie geofence’ów i pierwotnych aktywatorów
Ten fragment kodu używa klasy
GeofencingRequest
i jej zagnieżdżonej klasy
GeofencingRequestBuilder
do określania geofence’ów do monitorowania i ustawiania sposobu uruchamiania 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.
GEOFENCE_TRANSITION_ENTER
przejście uruchamia się, gdy urządzenie wejdzie do geoogrodzenia, a
GEOFENCE_TRANSITION_EXIT
przejście uruchamia się, gdy urządzenie opuści geoogrodzoną strefę. Określanie wartości
INITIAL_TRIGGER_ENTER
informuje Usługi lokalizacyjne, że
GEOFENCE_TRANSITION_ENTER
powinny zostać uruchomione, jeśli urządzenie znajduje się już w geoogrodzeniu.
W wielu przypadkach lepiej jest użyć tagu
INITIAL_TRIGGER_DWELL
, który uruchamia zdarzenia tylko wtedy, gdy użytkownik zatrzymuje się w geoogrodzeniu przez określony czas.
Takie podejście może pomóc w ograniczeniu „spamu z powiadomieniami” spowodowanego dużą liczbą powiadomień, gdy urządzenie na krótko wchodzi i wychodzi z geoogrodzenia. Inną strategią, która pozwoli Ci uzyskać najlepsze wyniki w przypadku geoogrodów, jest ustawienie minimalnego promienia 100 metrów. Pozwala to uwzględnić dokładność lokalizacji w typowych sieciach Wi-Fi, a także zmniejsza zużycie energii przez urządzenie.
Definiowanie odbiornika transmisji na potrzeby przejść w geofencingu
Intent
wysłany z Usług lokalizacji może wywoływać 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
jest dobrym sposobem na przetwarzanie przejścia na podstawie geoogrodzenia. BroadcastReceiver
aktualizuje się, gdy wystąpi zdarzenie, takie jak wejście lub wyjście z geoogrodzenia, i może rozpocząć długotrwałą pracę w tle.
Ten fragment kodu pokazuje, jak zdefiniować PendingIntent
, który uruchamia 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; }
Dodawanie geofence
Aby dodać geofence, użyj metody
.
Podaj obiekt GeofencingClient.addGeofences()
GeofencingRequest
i PendingIntent
.
Ten fragment kodu pokazuje przetwarzanie wyników:
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ść przez geofence
Gdy usługi lokalizacyjne wykryją, że użytkownik wszedł do geoogrodzenia lub z niego wyszedł, wysyłają Intent
zawarte w PendingIntent
, które zostało dołączone do żądania dodania geoogrodzeń. Odbiornik transmisji, taki jak GeofenceBroadcastReceiver
, zauważa, że wywołano Intent
, a następnie może uzyskać zdarzenie geofencingu z intencji, określić typ przejścia w ramach geofencingu i ustalić, które z zdefiniowanych geofence zostały uruchomione. Odbiorca transmisji może zlecić aplikacji rozpoczęcie wykonywania pracy w tle lub, jeśli zechce, wysłać powiadomienie jako dane wyjściowe.
Uwaga: w Androidzie 8.0 (poziom interfejsu API 26) i nowszych, jeśli aplikacja działa w tle podczas monitorowania geoogrodzenia, urządzenie reaguje na zdarzenia związane z geoogrodzeniem co kilka minut. Aby dowiedzieć się, jak dostosować aplikację do tych limitów odpowiedzi, przeczytaj artykuł Ograniczenia lokalizacji.
Poniższy fragment kodu pokazuje, jak zdefiniować element BroadcastReceiver
, który publikuje powiadomienie po przejściu na inny obszar geofencingu. 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 za pomocą PendingIntent
BroadcastReceiver
pobiera typ przejścia w geofencingu i sprawdza, czy jest to jedno ze zdarzeń, których aplikacja używa do uruchamiania 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 geoogrodzenia
Zatrzymanie monitorowania geoogrodzenia, gdy nie jest już potrzebne, może pomóc zaoszczędzić energię baterii i cykle procesora na urządzeniu. Możesz zatrzymać monitorowanie geofence
w głównej aktywności służącej do dodawania i usuwania geofence. Usunięcie geofence powoduje natychmiastowe zatrzymanie monitorowania. Interfejs API udostępnia metody umożliwiające usuwanie geofence’ów za pomocą identyfikatorów żądań lub poprzez usunięcie geofence’ów powiązanych z danym PendingIntent
.
Poniższy fragment kodu usuwa geofence według PendingIntent
, co powoduje zablokowanie wszystkich dalszych powiadomień, gdy urządzenie wchodzi do lub opuszcza wcześniej dodane geofence:
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 // ... } });
Geofencing można łączyć z innymi funkcjami wykorzystującymi lokalizację, np. z okresowymi aktualizacjami lokalizacji. Więcej informacji znajdziesz w innych lekcjach w tym kursie.
Stosuj sprawdzone metody geofencingu
W tej sekcji znajdziesz zalecenia dotyczące korzystania z geofencingu z API lokalizacji na Androida.
Zmniejsz zużycie energii
Aby zoptymalizować zużycie energii w aplikacjach korzystających z geofencingu, możesz użyć tych technik:
Ustaw czas reakcji na powiadomienia na wyższą wartość. Dzięki temu zmniejszysz zużycie energii, zwiększając opóźnienie alertów dotyczących geofence. Jeśli na przykład ustawisz wartość szybkości reakcji na 5 minut, aplikacja będzie sprawdzać alerty dotyczące wjazdu lub wyjazdu tylko raz na 5 minut. Ustawienie niższych wartości niekoniecznie oznacza, że użytkownicy otrzymają powiadomienie w tym czasie (na przykład jeśli ustawisz wartość 5 sekund, może minąć trochę więcej czasu, zanim użytkownik otrzyma alert).
Użyj większego promienia geoogrodzenia w przypadku lokalizacji, w których użytkownik spędza dużo czasu, na przykład domu lub pracy. Większy promień nie zmniejsza bezpośrednio zużycia energii, ale zmniejsza częstotliwość sprawdzania przez aplikację wejścia lub wyjścia, co pozwala zmniejszyć ogólne zużycie energii.
Wybierz optymalny promień geoogrodzenia
Aby uzyskać najlepsze wyniki, ustaw minimalny promień geoogrodzenia na 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 wewnątrz budynku, dokładność może wynosić nawet 5 metrów. Jeśli nie wiesz, czy w obrębie geoogrodzenia jest dostępna lokalizacja wewnątrz budynku, załóż, że dokładność lokalizacji Wi-Fi wynosi około 50 metrów.
Gdy lokalizacja Wi-Fi jest niedostępna (na przykład podczas jazdy po obszarach wiejskich), dokładność lokalizacji spada. Dokładność może wynosić od kilkuset metrów do kilku kilometrów. W takich przypadkach należy utworzyć geofence o większym promieniu.
Wyjaśnij użytkownikom, dlaczego Twoja aplikacja używa geofencingu
Ponieważ aplikacja korzysta z lokalizacji w tle, gdy używasz geofence, zastanów się, jakie korzyści przynosi ona użytkownikom. Wyjaśnij, dlaczego aplikacja potrzebuje tego dostępu, aby zwiększyć przejrzystość i zrozumienie.
Więcej informacji o sprawdzonych metodach związanych z dostępem do lokalizacji, w tym o geofencingu, znajdziesz na stronie Sprawdzone metody ochrony prywatności.
Używanie typu przejścia „czas trwania” w celu ograniczenia spamu z alertami
Jeśli podczas krótkiego przejazdu przez geofence otrzymujesz dużą liczbę alertów, najlepszym sposobem na zmniejszenie liczby alertów jest użycie typu przejścia
GEOFENCE_TRANSITION_DWELL
zamiast
GEOFENCE_TRANSITION_ENTER
. W ten sposób alert o zatrzymaniu jest wysyłany tylko wtedy, gdy użytkownik zatrzymuje się w geoogrodzeniu przez określony czas. Czas trwania możesz wybrać, ustawiając
opóźnienie na nękanie.
rejestrować geoogrodzenia ponownie tylko wtedy, gdy jest to konieczne;
Zarejestrowane geoogrodzenia 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 tych zdarzeniach:
- Usługi Google Play zostały uaktualnione.
- Usługi Google Play są zabijane i restartowane przez system z powodu ograniczenia zasobów.
- Proces lokalizacji ulega awarii.
Aplikacja musi ponownie zarejestrować geoogrodzenia, jeśli są one nadal potrzebne po tych zdarzeniach, ponieważ system nie może odzyskać geoogrodzeń w tych przypadkach:
- Urządzenie zostanie zrestartowane. Aplikacja powinna nasłuchiwać działania po uruchomieniu urządzenia, a potem ponownie zarejestrować wymagane geofence.
- Aplikacja zostanie odinstalowana i ponownie zainstalowana.
- Dane aplikacji zostaną wyczyszczone.
- dane Usług Google Play zostały wyczyszczone;
- Aplikacja otrzymała alert
GEOFENCE_NOT_AVAILABLE
. Zwykle dzieje się tak po wyłączeniu NLP (dostawcy lokalizacji sieci na Androidzie).
Rozwiązywanie problemów ze zdarzeniem wejścia na obszar geofencingu
Jeśli geofence nie są aktywowane, gdy urządzenie wchodzi na obszar geofence (nie jest aktywowany alert
GEOFENCE_TRANSITION_ENTER
), najpierw sprawdź, czy geofence są prawidłowo zarejestrowane zgodnie z instrukcjami podanymi w tym przewodniku.
Oto kilka możliwych przyczyn, dla których alerty nie działają zgodnie z oczekiwaniami:
- Dokładna lokalizacja nie jest dostępna w geoogrodzeniu lub geoogrodzeniu jest za małe. Na większości urządzeń usługa geofence do aktywowania geofence korzysta tylko z lokalizacji sieciowej. Usługa korzysta z tego podejścia, ponieważ lokalizacja sieci zużywa znacznie mniej energii, uzyskiwanie pojedynczych lokalizacji zajmuje mniej czasu, a co najważniejsze, jest 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ę „tylko skanowanie sieci Wi-Fi”, która umożliwia użytkownikom wyłączenie Wi-Fi, ale nadal zapewnia dobrą lokalizację sieci. Dobrą praktyką jest wyświetlenie użytkownikowi prompta i podanie skrótu do włączenia trybu Wi-Fi lub tylko skanowania Wi-Fi, jeśli oba są wyłączone. Użyj funkcji SettingsClient, aby mieć pewność, że ustawienia systemu urządzenia są prawidłowo skonfigurowane pod kątem optymalnego wykrywania lokalizacji.
Uwaga: jeśli Twoja aplikacja jest kierowana na Androida 10 (poziom interfejsu API 29) lub nowszego, nie możesz wywoływać bezpośrednio funkcji
WifiManager.setEnabled()
, chyba że jest to aplikacja systemowa lub kontroler zasad urządzenia (DPC). Zamiast tego użyj panelu ustawień.- Brak niezawodnego połączenia z siecią w strefie geograficznej. Jeśli nie ma stabilnego połączenia danych, alerty mogą nie być generowane. Dzieje się tak, ponieważ usługa geofence zależy od dostawcy lokalizacji sieci, który z kolei wymaga połączenia danych.
- Alerty mogą być opóźnione. Usługa geofence nie wysyła ciągle zapytań o lokalizację, dlatego opóźnienia w przychodzeniu alertów są możliwe. Zwykle opóźnienie wynosi mniej niż 2 minuty, a nawet mniej, gdy urządzenie się porusza. Jeśli obowiązują ograniczenia dotyczące lokalizacji, opóźnienie wynosi średnio 2–3 minuty. Jeśli urządzenie było nieruchome przez dłuższy czas, opóźnienie może wzrosnąć (do 6 minut).
Dodatkowe materiały
Aby dowiedzieć się więcej o geofencingu, zapoznaj się z tymi materiałami:
Próbki
Próbna aplikacja do tworzenia i monitorowania geoogrodów.