Tworzenie i monitorowanie geofencingu

Geofencing łączy ze sobą informacje o obecnej lokalizacji użytkownika z informacjami o odległości od miejsc, które mogą go zainteresować. Aby oznaczyć lokalizację interesującej Cię lokalizacji, musisz określić jej szerokość i długość geograficzną. Aby dostosować bliskość dodaj promień. Szerokość, długość i promień wyznaczają geofencing, tworząc okrągłego obszaru lub ogrodzenia wokół wybranej lokalizacji.

Możesz mieć wiele aktywnych geofence z limitem 100 na aplikację na użytkownika urządzenia. Dla każdej wartości geofence, możesz poprosić usługi lokalizacyjne o wysyłanie zdarzeń wejścia i wyjścia, czas oczekiwania w obszarze geofencingu, czyli zamieszanie przed wywołaniem zdarzenia. Możesz ograniczyć czas trwania dowolnej geofence, podając czas wygaśnięcia w milisekundach. Po upływie okresu ważności geoogrodzenia usługi lokalizacyjne automatycznie je usuwają.

Z tej lekcji dowiesz się, jak dodawać i usuwać geoogrodzenia oraz jak odbierać przejścia między geoogrodzeniami za pomocą BroadcastReceiver.

Uwaga: na urządzeniach Wear interfejsy Geofencing API nie wykorzystują w efektywny sposób . Nie zalecamy używania tych interfejsów API na Wear. Więcej informacji znajdziesz w artykule Oszczędzanie energii i baterii.

Konfigurowanie monitorowania geoogrodzenia

Aby poprosić o monitorowanie geofencingu, najpierw poproś o niezbędną uprawnień. Aby można było korzystać z geofencingu, aplikacja musi prosić o te uprawnienia:

Więcej informacji znajdziesz w przewodniku poprosić o dostęp do lokalizacji.

Jeśli chcesz używać BroadcastReceiver do słuchania przejść w geofence, dodaj element określający nazwę usługi. Ten element musi być element podrzędny 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:

KotlinJava
lateinit var geofencingClient: GeofencingClient

override fun onCreate(savedInstanceState: Bundle?) {
    // ...
    geofencingClient = LocationServices.getGeofencingClient(this)
}
private GeofencingClient geofencingClient;

@Override
public void onCreate(Bundle savedInstanceState) {
    // ...
    geofencingClient = LocationServices.getGeofencingClient(this);
}

Tworzenie i dodawanie geofence

Aplikacja musi utworzyć i dodać geofencje za pomocą klasy kreatora lokalizacji interfejsu API dla tworzenie obiektów Geofence i klasę wygodną do ich dodawania. 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 za pomocą funkcji Geofence.Builder utwórz geofence, ustawiając odpowiedni promień, czas trwania i typów przejść dla geofencingu. Aby na przykład wypełnić obiekt listy:

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

Ten przykład pobiera dane z pliku stałych. W praktyce aplikacje mogą dynamicznie tworzyć geoogrodzenia na podstawie lokalizacji użytkownika.

Określ geofence’y i pierwotne reguły

Ten fragment kodu używa klasy GeofencingRequest i zagnieżdżonej klasy GeofencingRequestBuilder w Możesz określić obszary geograficzne, które mają być monitorowane, i określić sposób wywoływania powiązanych zdarzeń geofencingu:

KotlinJava
private fun getGeofencingRequest(): GeofencingRequest {
    return GeofencingRequest.Builder().apply {
        setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
        addGeofences(geofenceList)
    }.build()
}
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 jest uruchamiane, gdy urządzenie znajdzie się w regionie geofencingu, a GEOFENCE_TRANSITION_EXIT przejście jest uruchamiane po zamknięciu geofencingu urządzenia. Podanie 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ć zamiast niego INITIAL_TRIGGER_DWELL, który wywołuje zdarzenia tylko wtedy, gdy użytkownik zatrzyma się na określony czas w obrębie geofencingu. Takie podejście może pomóc ograniczyć ilość spamu w alertach wynikające z powiadomień o dużej liczbie znaków, gdy urządzenie na chwilę włącza się i wyłącza funkcje geofence. Inną strategią uzyskiwania najlepszych wyników geofence to 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ść między geofence’ami

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. O BroadcastReceiver otrzymuje aktualizacje, gdy wystąpi zdarzenie, takie jak przejść do geofencingu lub z niego i może uruchomić długotrwałe działanie w tle; w naszej pracy.

Ten fragment kodu pokazuje, aby zdefiniować PendingIntent, który zaczyna się BroadcastReceiver:

KotlinJava
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)
    }
}
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ć geofencje, użyj metody GeofencingClient.addGeofences(). Podaj obiekt GeofencingRequestPendingIntent. Ten fragment kodu pokazuje przetwarzanie wyników:

KotlinJava
geofencingClient?.addGeofences(getGeofencingRequest(), geofencePendingIntent)?.run {
    addOnSuccessListener {
        // Geofences added
        // ...
    }
    addOnFailureListener {
        // Failed to add geofences
        // ...
    }
}
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 włączył geofence lub go opuściła, wysyła pole Intent zawarte w PendingIntent które masz uwzględnione w prośbie o dodanie geofencingu. Odbiornik – np. Aplikacja GeofenceBroadcastReceiver zauważa, że został wywołany Intent, mogą następnie uzyskać z intencji zdarzenie geofencingu, określić typ przejść geofencingu, i określić, który ze zdefiniowanych obszarów geograficznych został aktywowany. Transmisja odbiorca może przekierować aplikację tak, aby rozpoczęła pracę w tle lub wyślij powiadomienie jako dane wyjściowe.

Uwaga: w Androidzie 8.0 (poziom interfejsu API 26) i nowszych, jeśli aplikacja która działa w tle podczas monitorowania geofencingu, odpowiada na zdarzenia geofencingu co kilka minut. Aby dowiedzieć się, jak dostosować swoją 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 przez geofence. Gdy użytkownik kliknie powiadomienie, pojawi się główna aktywność w aplikacji:

KotlinJava
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))
        }
    }
}
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ą interfejsu PendingIntent BroadcastReceiver otrzymuje typ przejścia geofencingu, sprawdza, czy jest to jedno ze zdarzeń używanych przez aplikację do wywoływania powiadomień – albo GEOFENCE_TRANSITION_ENTER lub GEOFENCE_TRANSITION_EXIT w tej sprawie. Następnie usługa wysyła powiadomienie i rejestruje szczegóły przejścia.

Zatrzymaj monitorowanie geofencingu

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 geoogrodzenia za pomocą funkcji PendingIntent, co powoduje zablokowanie wszystkich dalszych powiadomień, gdy urządzenie wchodzi lub opuszcza wcześniej dodane geoogrodzenia:

KotlinJava
geofencingClient?.removeGeofences(geofencePendingIntent)?.run {
    addOnSuccessListener {
        // Geofences removed
        // ...
    }
    addOnFailureListener {
        // Failed to remove geofences
        // ...
    }
}
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ę, takimi jak okresowe aktualizacje lokalizacji. Więcej informacji znajdziesz w innych lekcjach w tym kursie.

Korzystanie ze sprawdzonych metod dotyczących geofencingu

W tej sekcji znajdziesz zalecenia dotyczące używania geofencingu w lokalizacji. Interfejsy API na Androida.

Zmniejsz zużycie energii

Aby zoptymalizować zużycie energii w aplikacjach korzystających z geofencingu, możesz skorzystać z tych metod:

  • Ustaw reagowania na powiadomienia na wyższą wartość. Pozwala to zmniejszyć zużycie energii, ponieważ zwiększając czas oczekiwania na alerty geofencingu. Jeśli np. ustawisz wartość responsywności na pięć a aplikacja sprawdza alert wejścia i wyjścia co 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).

  • ustawić większy promień geofencingu w lokalizacjach, w których użytkownik spędza dużo czasu; takich jak dom lub praca. Większy promień nie zmniejsza bezpośrednio zużycia energii, ale zmniejsza częstotliwość sprawdzania przez aplikację, czy użytkownik wchodzi lub wychodzi z obszaru, co pozwala zmniejszyć ogólne zużycie energii.

Wybierz optymalny promień geoogrodzenia

Aby uzyskać najlepsze wyniki, ustaw minimalny promień geofence w zakresie 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. Chyba że wiesz, że wewnątrz budynku lokalizacja jest dostępna w obrębie geofencingu, załóżmy, że dokładność lokalizacji Wi-Fi jest 50 metrów.

Jeśli sieć Wi-Fi jest niedostępna (np. jedziesz samochodem na obszarze wiejskim), dokładność lokalizacji jest mniejsza. Zakres dokładności może wynosić od kilkuset metrów kilka 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 dziecku, dlaczego. aplikacja potrzebuje tego dostępu, aby zwiększyć przejrzystość i zrozumienie użytkowników.

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ótkiej przejeżdżania obok geofencingu otrzymujesz dużą liczbę alertów, zmniejsz liczbę alertów, użyj typu przejścia GEOFENCE_TRANSITION_DWELL zamiast GEOFENCE_TRANSITION_ENTER. Dzięki temu alert dotyczący mieszkania jest wysyłany tylko wtedy, gdy użytkownik przestaje działać. w obrębie geofencingu w danym okresie. Czas trwania możesz wybrać, ustawiając opóźnienie w pojawianiu się treści.

Ponowna rejestracja geofencingu tylko wtedy, gdy jest to wymagane

Zarejestrowane geoogrodzenia są przechowywane w procesie com.google.process.location należącym do pakietu com.google.android.gms. Aplikacja nie musi nic robić do obsługi tych zdarzeń, bo system przywraca geofencje po tych zdarzeniach:

  • Usługi Google Play zostały uaktualnione.
  • Usługi Google Play są zatrzymywane i ponowicie uruchamiane 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ć zakończenia uruchamiania urządzenia, a następnie – zarejestrować wymagane geofence.
  • Aplikacja zostanie odinstalowana i ponownie zainstalowana.
  • Dane aplikacji zostaną wyczyszczone.
  • Dane Usług Google Play zostały wyczyszczone.
  • Aplikacja otrzymała GEOFENCE_NOT_AVAILABLE alert. Zwykle dzieje się tak po wyłączeniu NLP (dostawcy lokalizacji sieciowej na Androida).

Rozwiązywanie problemów ze zdarzeniem wejścia na obszar geofencingu

Jeśli geoogrodzenia nie są aktywowane, gdy urządzenie wjeżdża na obszar geoogrodzenia (nie jest wysyłany alert GEOFENCE_TRANSITION_ENTER), najpierw sprawdź, czy geoogrodzenia są prawidłowo zarejestrowane zgodnie z instrukcjami 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, szybciej uzyskuje poszczególne lokalizacje i co najważniejsze, jest dostępna w pomieszczeniach.
  • Wi-Fi na urządzeniu jest wyłączone. 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 wersji Android 4.3 (poziom interfejsu API 18) dodaliśmy funkcję „tylko skanowanie sieci Wi-Fi”, która umożliwia użytkownikom wyłączenie Wi-Fi przy jednoczesnym uzyskaniu dobrej lokalizacji sieci. To dobrze ćwiczenie promptów i udostępniania mu skrótu umożliwiającego włączenie tylko skanowania Wi-Fi lub Wi-Fi , jeśli oba tryby są wyłączone. Użyj formatu SettingsClient, aby zapewnić odpowiednią konfigurację ustawień systemowych urządzenia. wykrywanie 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ń.

  • W obrębie geofencingu nie ma niezawodnego połączenia sieciowego. Jeśli Brak niezawodnego połączenia do transmisji danych, mogą nie być generowane alerty. Dzieje się tak, ponieważ usługa geofence zależy od operatora lokalizacji, co z kolei wymaga połączenia transmisji danych.
  • Ostrzeżenia 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. Zazwyczaj opóźnienie jest mniejsze niż 2. nawet mniej, gdy urządzenie jest w ruchu. Jeśli obowiązują ograniczenia dotyczące korzystania z 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

Więcej informacji o geofencingu znajdziesz w tych materiałach:

Próbki

Próbna aplikacja do tworzenia i monitorowania geoogrodów.