Геозона объединяет осведомленность о текущем местоположении пользователя с осведомленностью о близости пользователя к местам, которые могут представлять интерес. Чтобы отметить место интереса, вы указываете его широту и долготу. Чтобы настроить близость для местоположения, вы добавляете радиус. Широта, долгота и радиус определяют геозону, создавая круговую область или забор вокруг места интереса.
Вы можете иметь несколько активных геозон с ограничением в 100 на приложение для каждого пользователя устройства. Для каждой геозоны вы можете попросить Службы определения местоположения отправлять вам события входа и выхода или можете указать длительность ожидания или задержки в пределах области геозоны перед запуском события. Вы можете ограничить длительность любой геозоны, указав длительность истечения в миллисекундах. После истечения срока действия геозоны Службы определения местоположения автоматически удаляют ее.

В этом уроке показано, как добавлять и удалять геозоны, а затем прослушивать переходы между геозонами с помощью BroadcastReceiver
.
Примечание: На устройствах Wear API Geofencing неэффективно используют энергию. Мы не рекомендуем использовать эти API на Wear. Прочитайте раздел Экономия энергии и батареи для получения дополнительной информации.
Настройка для мониторинга геозоны
Первый шаг в запросе мониторинга геозоны — запрос необходимых разрешений. Чтобы использовать геозону, ваше приложение должно запросить следующее:
-
ACCESS_FINE_LOCATION
-
ACCESS_BACKGROUND_LOCATION
, если ваше приложение предназначено для Android 10 (уровень API 29) или выше
Чтобы узнать больше, ознакомьтесь с руководством по запросу разрешений на определение местоположения .
Если вы хотите использовать BroadcastReceiver
для прослушивания переходов геозон, добавьте элемент, указывающий имя сервиса. Этот элемент должен быть дочерним элементом элемента <application>
:
<application android:allowBackup="true"> ... <receiver android:name=".GeofenceBroadcastReceiver"/> <application/>
Для доступа к API местоположения вам необходимо создать экземпляр клиента Geofencing. Чтобы узнать, как подключить вашего клиента:
Котлин
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); }
Создание и добавление геозон
Вашему приложению необходимо создавать и добавлять геозоны с помощью класса builder API местоположения для создания объектов Geofence и класса удобства для их добавления. Кроме того, для обработки намерений, отправленных из Location Services при переходах через геозоны, вы можете определить PendingIntent
, как показано в этом разделе.
Примечание: На однопользовательских устройствах существует ограничение в 100 геозон на приложение. Для многопользовательских устройств ограничение составляет 100 геозон на приложение на пользователя устройства.
Создание объектов геозоны
Сначала используйте Geofence.Builder
для создания геозоны, установив желаемый радиус, длительность и типы переходов для геозоны. Например, чтобы заполнить объект списка:
Котлин
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());
Этот пример извлекает данные из файла констант. На практике приложения могут динамически создавать геозоны на основе местоположения пользователя.
Укажите геозоны и начальные триггеры
В следующем фрагменте используется класс GeofencingRequest
и его вложенный класс GeofencingRequestBuilder
для указания геозон для мониторинга и настройки того, как будут запускаться связанные с ними события геозон:
Котлин
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(); }
В этом примере показано использование двух триггеров геозоны. Переход GEOFENCE_TRANSITION_ENTER
срабатывает, когда устройство входит в геозону, а переход GEOFENCE_TRANSITION_EXIT
срабатывает, когда устройство выходит из геозоны. Указание INITIAL_TRIGGER_ENTER
сообщает службам определения местоположения, что GEOFENCE_TRANSITION_ENTER
должен срабатывать, если устройство уже находится внутри геозоны.
Во многих случаях может быть предпочтительнее использовать вместо этого INITIAL_TRIGGER_DWELL
, который запускает события только тогда, когда пользователь останавливается на определенное время в пределах геозоны. Такой подход может помочь сократить «спам оповещений», возникающий из-за большого количества уведомлений, когда устройство кратковременно входит и выходит из геозон. Другая стратегия для получения наилучших результатов от ваших геозон — установить минимальный радиус в 100 метров. Это помогает учитывать точность определения местоположения типичных сетей Wi-Fi, а также помогает снизить энергопотребление устройства.
Определить приемник вещания для переходов через геозоны
Intent
, отправленный из Location Services, может инициировать различные действия в вашем приложении, но вы не должны запускать его для запуска активности или фрагмента, поскольку компоненты должны становиться видимыми только в ответ на действие пользователя. Во многих случаях BroadcastReceiver
является хорошим способом обработки перехода геозоны. BroadcastReceiver
получает обновления, когда происходит событие, например, переход в геозону или из нее, и может запустить длительную фоновую работу.
В следующем фрагменте показано, как определить PendingIntent
, который запускает BroadcastReceiver
:
Котлин
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; }
Добавить геозоны
Для добавления геозон используйте метод
. Предоставьте объект GeofencingClient.addGeofences()
GeofencingRequest
и PendingIntent
. Следующий фрагмент демонстрирует обработку результатов:
Котлин
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 // ... } });
Обработка переходов геозон
Когда службы определения местоположения обнаруживают, что пользователь вошел в геозону или вышел из нее, они отправляют Intent
, содержащийся в PendingIntent
, который вы включили в запрос на добавление геозон. Широковещательный приемник, такой как GeofenceBroadcastReceiver
замечает, что Intent
был вызван, и может затем получить событие геозоны из намерения, определить тип перехода(ов) геозоны и определить, какая из определенных геозон была запущена. Широковещательный приемник может дать команду приложению начать выполнять фоновую работу или, при желании, отправить уведомление в качестве вывода.
Примечание: на Android 8.0 (уровень API 26) и выше, если приложение работает в фоновом режиме во время мониторинга геозоны, то устройство реагирует на события геозоны каждые пару минут. Чтобы узнать, как адаптировать свое приложение к этим ограничениям реагирования, см. Ограничения фонового местоположения .
Следующий фрагмент показывает, как определить BroadcastReceiver
, который публикует уведомление, когда происходит переход геозоны. Когда пользователь нажимает на уведомление, появляется основная активность приложения:
Котлин
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)); } } }
После обнаружения события перехода через PendingIntent
BroadcastReceiver
получает тип перехода геозоны и проверяет, является ли это одним из событий, которые приложение использует для запуска уведомлений — в данном случае GEOFENCE_TRANSITION_ENTER
или GEOFENCE_TRANSITION_EXIT
. Затем служба отправляет уведомление и регистрирует сведения о переходе.
Остановить мониторинг геозоны
Остановка мониторинга геозон, когда он больше не нужен или нежелателен, может помочь сэкономить заряд батареи и циклы ЦП на устройстве. Вы можете остановить мониторинг геозон в основной активности, используемой для добавления и удаления геозон; удаление геозоны немедленно останавливает его. API предоставляет методы для удаления геозон либо по идентификаторам запросов, либо путем удаления геозон, связанных с заданным PendingIntent
.
Следующий фрагмент удаляет геозоны с помощью PendingIntent
, останавливая все дальнейшие уведомления, когда устройство входит или выходит из ранее добавленных геозон:
Котлин
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 // ... } });
Вы можете объединить геозонирование с другими функциями, учитывающими местоположение, такими как периодические обновления местоположения. Для получения дополнительной информации см. другие уроки в этом классе.
Используйте лучшие практики для геозонирования
В этом разделе изложены рекомендации по использованию геозон с API определения местоположения для Android.
Снижение энергопотребления
Для оптимизации энергопотребления в приложениях, использующих геозонирование, можно использовать следующие методы:
Установите более высокое значение для скорости реагирования уведомлений . Это улучшает энергопотребление за счет увеличения задержки оповещений о геозонах. Например, если вы установите значение скорости реагирования в пять минут, ваше приложение будет проверять наличие оповещения о входе или выходе только один раз каждые пять минут. Установка более низких значений не обязательно означает, что пользователи будут уведомлены в течение этого периода времени (например, если вы установите значение в 5 секунд, получение оповещения может занять немного больше времени).
Используйте больший радиус геозоны для мест, где пользователь проводит значительное количество времени, например, дома или на работе. Хотя больший радиус не снижает потребление энергии напрямую, он снижает частоту, с которой приложение проверяет вход или выход, эффективно снижая общее потребление энергии.
Выберите оптимальный радиус для вашей геозоны
Для достижения наилучших результатов минимальный радиус геозоны должен быть установлен в диапазоне от 100 до 150 метров. При наличии Wi-Fi точность определения местоположения обычно составляет от 20 до 50 метров. При наличии местоположения в помещении диапазон точности может составлять всего 5 метров. Если вы не знаете, доступно ли местоположение в помещении внутри геозоны, предположите, что точность определения местоположения Wi-Fi составляет около 50 метров.
Когда местоположение Wi-Fi недоступно (например, когда вы едете по сельской местности), точность определения местоположения ухудшается. Диапазон точности может достигать нескольких сотен метров или нескольких километров. В таких случаях следует создавать геозоны с большим радиусом.
Объясните пользователям, почему ваше приложение использует геозонирование
Поскольку ваше приложение получает доступ к местоположению в фоновом режиме при использовании геозонирования, подумайте, как ваше приложение обеспечивает преимущества для пользователей. Объясните им четко, почему вашему приложению нужен этот доступ, чтобы повысить понимание и прозрачность для пользователей.
Дополнительную информацию о передовых методах доступа к местоположению, включая геозонирование, можно найти на странице передовых методов обеспечения конфиденциальности .
Используйте тип перехода с задержкой, чтобы уменьшить количество спама в оповещениях
Если вы получаете большое количество оповещений при кратковременном проезде мимо геозоны, лучшим способом уменьшить их количество является использование типа перехода GEOFENCE_TRANSITION_DWELL
вместо GEOFENCE_TRANSITION_ENTER
. Таким образом, оповещение о пребывании будет отправляться только тогда, когда пользователь останавливается внутри геозоны на определенный период времени. Вы можете выбрать продолжительность, установив задержку праздношатания .
Перерегистрируйте геозоны только при необходимости.
Зарегистрированные геозоны хранятся в процессе com.google.process.location
, принадлежащем пакету com.google.android.gms
. Приложению не нужно ничего делать для обработки следующих событий, поскольку система восстанавливает геозоны после этих событий:
- Сервисы Google Play обновлены.
- Службы Google Play останавливаются и перезапускаются системой из-за ограничения ресурсов.
- Процесс определения местоположения дает сбой.
Приложение должно повторно зарегистрировать геозоны, если они все еще нужны после следующих событий, поскольку система не может восстановить геозоны в следующих случаях:
- Устройство перезагружено. Приложение должно прослушивать действие завершения загрузки устройства, а затем повторно регистрировать требуемые геозоны.
- Приложение удалено и установлено заново.
- Данные приложения очищены.
- Данные сервисов Google Play очищены.
- Приложение получило оповещение
GEOFENCE_NOT_AVAILABLE
. Обычно это происходит после отключения NLP (поставщика сетевого местоположения Android).
Устранение неполадок, связанных с событием входа в геозону
Если геозоны не срабатывают при входе устройства в геозону (не срабатывает оповещение GEOFENCE_TRANSITION_ENTER
), сначала убедитесь, что ваши геозоны зарегистрированы правильно, как описано в этом руководстве.
Вот несколько возможных причин, по которым оповещения не работают должным образом:
- Точное местоположение недоступно внутри вашей геозоны или геозона слишком мала. На большинстве устройств служба геозоны использует только сетевое местоположение для срабатывания геозоны. Служба использует этот подход, поскольку сетевое местоположение потребляет гораздо меньше энергии, требуется меньше времени для получения дискретных местоположений, и, что самое важное, оно доступно в помещении.
Wi-Fi выключен на устройстве. Включение Wi-Fi может значительно повысить точность определения местоположения, поэтому если Wi-Fi выключен, ваше приложение может никогда не получать оповещения о геозоне в зависимости от нескольких настроек, включая радиус геозоны, модель устройства или версию Android. Начиная с Android 4.3 (уровень API 18), мы добавили возможность «Режима только сканирования Wi-Fi», которая позволяет пользователям отключать Wi-Fi, но по-прежнему получать хорошее сетевое местоположение. Хорошей практикой является предложение пользователю и предоставление ярлыка для включения Wi-Fi или режима только сканирования Wi-Fi, если оба они отключены. Используйте SettingsClient , чтобы убедиться, что системные настройки устройства правильно настроены для оптимального определения местоположения.
Примечание: Если ваше приложение предназначено для Android 10 (уровень API 29) или выше, вы не можете вызвать
WifiManager.setEnabled()
напрямую, если только ваше приложение не является системным приложением или контроллером политики устройства (DPC) . Вместо этого используйте панель настроек .- Внутри вашей геозоны нет надежного сетевого подключения. Если нет надежного подключения к данным, оповещения могут не генерироваться. Это связано с тем, что служба геозоны зависит от поставщика сетевого местоположения, который в свою очередь требует подключения к данным.
- Оповещения могут запаздывать. Служба геозоны не запрашивает местоположение непрерывно, поэтому при получении оповещений следует ожидать некоторой задержки. Обычно задержка составляет менее 2 минут, а когда устройство движется, то даже меньше. Если действуют ограничения фонового местоположения , задержка составляет в среднем около 2-3 минут. Если устройство было неподвижно в течение значительного периода времени, задержка может увеличиться (до 6 минут).
Дополнительные ресурсы
Чтобы узнать больше о Geofencing, ознакомьтесь со следующими материалами:
Образцы
Пример приложения для создания и мониторинга геозон.
,Геозона объединяет осведомленность о текущем местоположении пользователя с осведомленностью о близости пользователя к местам, которые могут представлять интерес. Чтобы отметить место интереса, вы указываете его широту и долготу. Чтобы настроить близость для местоположения, вы добавляете радиус. Широта, долгота и радиус определяют геозону, создавая круговую область или забор вокруг места интереса.
Вы можете иметь несколько активных геозон с ограничением в 100 на приложение для каждого пользователя устройства. Для каждой геозоны вы можете попросить Службы определения местоположения отправлять вам события входа и выхода или можете указать длительность ожидания или задержки в пределах области геозоны перед запуском события. Вы можете ограничить длительность любой геозоны, указав длительность истечения в миллисекундах. После истечения срока действия геозоны Службы определения местоположения автоматически удаляют ее.

В этом уроке показано, как добавлять и удалять геозоны, а затем прослушивать переходы между геозонами с помощью BroadcastReceiver
.
Примечание: На устройствах Wear API Geofencing неэффективно используют энергию. Мы не рекомендуем использовать эти API на Wear. Прочитайте раздел Экономия энергии и батареи для получения дополнительной информации.
Настройка для мониторинга геозоны
Первый шаг в запросе мониторинга геозоны — запрос необходимых разрешений. Чтобы использовать геозону, ваше приложение должно запросить следующее:
-
ACCESS_FINE_LOCATION
-
ACCESS_BACKGROUND_LOCATION
, если ваше приложение предназначено для Android 10 (уровень API 29) или выше
Чтобы узнать больше, ознакомьтесь с руководством по запросу разрешений на определение местоположения .
Если вы хотите использовать BroadcastReceiver
для прослушивания переходов геозон, добавьте элемент, указывающий имя сервиса. Этот элемент должен быть дочерним элементом элемента <application>
:
<application android:allowBackup="true"> ... <receiver android:name=".GeofenceBroadcastReceiver"/> <application/>
Для доступа к API местоположения вам необходимо создать экземпляр клиента Geofencing. Чтобы узнать, как подключить вашего клиента:
Котлин
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); }
Создание и добавление геозон
Вашему приложению необходимо создавать и добавлять геозоны с помощью класса builder API местоположения для создания объектов Geofence и класса удобства для их добавления. Кроме того, для обработки намерений, отправленных из Location Services при переходах через геозоны, вы можете определить PendingIntent
, как показано в этом разделе.
Примечание: На однопользовательских устройствах существует ограничение в 100 геозон на приложение. Для многопользовательских устройств ограничение составляет 100 геозон на приложение на пользователя устройства.
Создание объектов геозоны
Сначала используйте Geofence.Builder
для создания геозоны, установив желаемый радиус, длительность и типы переходов для геозоны. Например, чтобы заполнить объект списка:
Котлин
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());
Этот пример извлекает данные из файла констант. На практике приложения могут динамически создавать геозоны на основе местоположения пользователя.
Укажите геозоны и начальные триггеры
В следующем фрагменте используется класс GeofencingRequest
и его вложенный класс GeofencingRequestBuilder
для указания геозон для мониторинга и настройки того, как будут запускаться связанные с ними события геозон:
Котлин
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(); }
В этом примере показано использование двух триггеров геозоны. Переход GEOFENCE_TRANSITION_ENTER
срабатывает, когда устройство входит в геозону, а переход GEOFENCE_TRANSITION_EXIT
срабатывает, когда устройство выходит из геозоны. Указание INITIAL_TRIGGER_ENTER
сообщает службам определения местоположения, что GEOFENCE_TRANSITION_ENTER
должен срабатывать, если устройство уже находится внутри геозоны.
Во многих случаях может быть предпочтительнее использовать вместо этого INITIAL_TRIGGER_DWELL
, который запускает события только тогда, когда пользователь останавливается на определенное время в пределах геозоны. Такой подход может помочь сократить «спам оповещений», возникающий из-за большого количества уведомлений, когда устройство кратковременно входит и выходит из геозон. Другая стратегия для получения наилучших результатов от ваших геозон — установить минимальный радиус в 100 метров. Это помогает учитывать точность определения местоположения типичных сетей Wi-Fi, а также помогает снизить энергопотребление устройства.
Определить приемник вещания для переходов через геозоны
Intent
, отправленный из Location Services, может инициировать различные действия в вашем приложении, но вы не должны запускать его для запуска активности или фрагмента, поскольку компоненты должны становиться видимыми только в ответ на действие пользователя. Во многих случаях BroadcastReceiver
является хорошим способом обработки перехода геозоны. BroadcastReceiver
получает обновления, когда происходит событие, например, переход в геозону или из нее, и может запустить длительную фоновую работу.
В следующем фрагменте показано, как определить PendingIntent
, который запускает BroadcastReceiver
:
Котлин
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; }
Добавить геозоны
Для добавления геозон используйте метод
. Предоставьте объект GeofencingClient.addGeofences()
GeofencingRequest
и PendingIntent
. Следующий фрагмент демонстрирует обработку результатов:
Котлин
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 // ... } });
Обработка переходов геозон
Когда службы определения местоположения обнаруживают, что пользователь вошел в геозону или вышел из нее, они отправляют Intent
, содержащийся в PendingIntent
, который вы включили в запрос на добавление геозон. Широковещательный приемник, такой как GeofenceBroadcastReceiver
замечает, что Intent
был вызван, и может затем получить событие геозоны из намерения, определить тип перехода(ов) геозоны и определить, какая из определенных геозон была запущена. Широковещательный приемник может дать команду приложению начать выполнять фоновую работу или, при желании, отправить уведомление в качестве вывода.
Примечание: на Android 8.0 (уровень API 26) и выше, если приложение работает в фоновом режиме во время мониторинга геозоны, то устройство реагирует на события геозоны каждые пару минут. Чтобы узнать, как адаптировать свое приложение к этим ограничениям реагирования, см. Ограничения фонового местоположения .
Следующий фрагмент показывает, как определить BroadcastReceiver
, который публикует уведомление, когда происходит переход геозоны. Когда пользователь нажимает на уведомление, появляется основная активность приложения:
Котлин
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)); } } }
После обнаружения события перехода через PendingIntent
BroadcastReceiver
получает тип перехода геозоны и проверяет, является ли это одним из событий, которые приложение использует для запуска уведомлений — в данном случае GEOFENCE_TRANSITION_ENTER
или GEOFENCE_TRANSITION_EXIT
. Затем служба отправляет уведомление и регистрирует сведения о переходе.
Остановить мониторинг геозоны
Остановка мониторинга геозон, когда он больше не нужен или нежелателен, может помочь сэкономить заряд батареи и циклы ЦП на устройстве. Вы можете остановить мониторинг геозон в основной активности, используемой для добавления и удаления геозон; удаление геозоны немедленно останавливает его. API предоставляет методы для удаления геозон либо по идентификаторам запросов, либо путем удаления геозон, связанных с заданным PendingIntent
.
Следующий фрагмент удаляет геозоны с помощью PendingIntent
, останавливая все дальнейшие уведомления, когда устройство входит или выходит из ранее добавленных геозон:
Котлин
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 // ... } });
Вы можете объединить геозонирование с другими функциями, учитывающими местоположение, такими как периодические обновления местоположения. Для получения дополнительной информации см. другие уроки в этом классе.
Используйте лучшие практики для геозонирования
В этом разделе изложены рекомендации по использованию геозон с API определения местоположения для Android.
Снижение энергопотребления
Для оптимизации энергопотребления в приложениях, использующих геозонирование, можно использовать следующие методы:
Установите более высокое значение для скорости реагирования уведомлений . Это улучшает энергопотребление за счет увеличения задержки оповещений о геозонах. Например, если вы установите значение скорости реагирования в пять минут, ваше приложение будет проверять наличие оповещения о входе или выходе только один раз каждые пять минут. Установка более низких значений не обязательно означает, что пользователи будут уведомлены в течение этого периода времени (например, если вы установите значение в 5 секунд, получение оповещения может занять немного больше времени).
Используйте больший радиус геозоны для мест, где пользователь проводит значительное количество времени, например, дома или на работе. Хотя больший радиус не снижает потребление энергии напрямую, он снижает частоту, с которой приложение проверяет вход или выход, эффективно снижая общее потребление энергии.
Выберите оптимальный радиус для вашей геозоны
Для достижения наилучших результатов минимальный радиус геозоны должен быть установлен в диапазоне от 100 до 150 метров. При наличии Wi-Fi точность определения местоположения обычно составляет от 20 до 50 метров. При наличии местоположения в помещении диапазон точности может составлять всего 5 метров. Если вы не знаете, доступно ли местоположение в помещении внутри геозоны, предположите, что точность определения местоположения Wi-Fi составляет около 50 метров.
Когда местоположение Wi-Fi недоступно (например, когда вы едете по сельской местности), точность определения местоположения ухудшается. Диапазон точности может достигать нескольких сотен метров или нескольких километров. В таких случаях следует создавать геозоны с большим радиусом.
Объясните пользователям, почему ваше приложение использует геозонирование
Поскольку ваше приложение получает доступ к местоположению в фоновом режиме при использовании геозонирования, подумайте, как ваше приложение обеспечивает преимущества для пользователей. Объясните им четко, почему вашему приложению нужен этот доступ, чтобы повысить понимание и прозрачность для пользователей.
Дополнительную информацию о передовых методах доступа к местоположению, включая геозонирование, можно найти на странице передовых методов обеспечения конфиденциальности .
Используйте тип перехода с задержкой, чтобы уменьшить количество спама в оповещениях
Если вы получаете большое количество оповещений при кратковременном проезде мимо геозоны, лучшим способом уменьшить их количество является использование типа перехода GEOFENCE_TRANSITION_DWELL
вместо GEOFENCE_TRANSITION_ENTER
. Таким образом, оповещение о пребывании будет отправляться только тогда, когда пользователь останавливается внутри геозоны на определенный период времени. Вы можете выбрать продолжительность, установив задержку праздношатания .
Перерегистрируйте геозоны только при необходимости.
Зарегистрированные геозоны хранятся в процессе com.google.process.location
, принадлежащем пакету com.google.android.gms
. Приложению не нужно ничего делать для обработки следующих событий, поскольку система восстанавливает геозоны после этих событий:
- Сервисы Google Play обновлены.
- Службы Google Play останавливаются и перезапускаются системой из-за ограничения ресурсов.
- Процесс определения местоположения дает сбой.
Приложение должно повторно зарегистрировать геозоны, если они все еще нужны после следующих событий, поскольку система не может восстановить геозоны в следующих случаях:
- Устройство перезагружено. Приложение должно прослушивать действие завершения загрузки устройства, а затем повторно регистрировать требуемые геозоны.
- Приложение удалено и установлено заново.
- Данные приложения очищены.
- Данные сервисов Google Play очищены.
- Приложение получило оповещение
GEOFENCE_NOT_AVAILABLE
. Обычно это происходит после отключения NLP (поставщика сетевого местоположения Android).
Устранение неполадок, связанных с событием входа в геозону
Если геозоны не срабатывают при входе устройства в геозону (не срабатывает оповещение GEOFENCE_TRANSITION_ENTER
), сначала убедитесь, что ваши геозоны зарегистрированы правильно, как описано в этом руководстве.
Вот несколько возможных причин, по которым оповещения не работают должным образом:
- Точное местоположение недоступно внутри вашей геозоны или геозона слишком мала. На большинстве устройств служба геозоны использует только сетевое местоположение для срабатывания геозоны. Служба использует этот подход, поскольку сетевое местоположение потребляет гораздо меньше энергии, требуется меньше времени для получения дискретных местоположений, и, что самое важное, оно доступно в помещении.
Wi-Fi выключен на устройстве. Включение Wi-Fi может значительно повысить точность определения местоположения, поэтому если Wi-Fi выключен, ваше приложение может никогда не получать оповещения о геозоне в зависимости от нескольких настроек, включая радиус геозоны, модель устройства или версию Android. Начиная с Android 4.3 (уровень API 18), мы добавили возможность «Режима только сканирования Wi-Fi», которая позволяет пользователям отключать Wi-Fi, но по-прежнему получать хорошее сетевое местоположение. Хорошей практикой является предложение пользователю и предоставление ярлыка для включения Wi-Fi или режима только сканирования Wi-Fi, если оба они отключены. Используйте SettingsClient , чтобы убедиться, что системные настройки устройства правильно настроены для оптимального определения местоположения.
Примечание: Если ваше приложение предназначено для Android 10 (уровень API 29) или выше, вы не можете вызвать
WifiManager.setEnabled()
напрямую, если только ваше приложение не является системным приложением или контроллером политики устройства (DPC) . Вместо этого используйте панель настроек .- Внутри вашей геозоны нет надежного сетевого подключения. Если нет надежного подключения к данным, оповещения могут не генерироваться. Это связано с тем, что служба геозоны зависит от поставщика сетевого местоположения, который в свою очередь требует подключения к данным.
- Оповещения могут запаздывать. Служба геозоны не запрашивает местоположение непрерывно, поэтому при получении оповещений следует ожидать некоторой задержки. Обычно задержка составляет менее 2 минут, а когда устройство движется, то даже меньше. Если действуют ограничения фонового местоположения , задержка составляет в среднем около 2-3 минут. Если устройство было неподвижно в течение значительного периода времени, задержка может увеличиться (до 6 минут).
Дополнительные ресурсы
Чтобы узнать больше о Geofencing, ознакомьтесь со следующими материалами:
Образцы
Пример приложения для создания и мониторинга геозон.