- Работа с геозонами (geofences) в Android
- Что такое Location APIs?
- Задача
- Алгоритм
- К делу!
- На этом всё!
- Geofencing in Android
- What is Geofence?
- Geofence Transitions
- When geofences required Re-register?
- How to Work With Geofences on Android
- 1. Geofences on Android
- Geofence Interface
- Geofence Transitions
- GeofenceRequest
- GeofencingApi
- 2. Creating a Geofencing App
- Step 1: Project Setup
- Step 2: Permissions
- Step 3: Creating the Layout
- Step 4: Google Maps API Key
- Step 5: GoogleApiClient
- Step 6: FusedLocationProviderApi
- Step 7: GoogleMap Markers
- Step 8: Creating a Geofence
- Step 9: Geofence Transition Service
- 3. Testing
- Testing on a Virtual Device
- Conclusion
Работа с геозонами (geofences) в Android
Что такое Location APIs?
Location APIs являются частью Google Play сервисов, которая предназначена для создания приложений работающих с местоположением устройства. В отличие от подобных функций в LocationManager, данные API отличаются улучшенным энергосбережением. В данный момент доступна следующая функциональность: определение местоположения устройства, работа с геозонами и распознавание активности пользователя. Определение местоположения позволяет балансировать между точностью определения и потреблением энергии, а также предоставляет доступ к наиболее частым местоположениям. Распознавание активности позволяет узнать, что делает пользователь устройства: едет на машине, едет на велосипеде, идет пешком или находится на одном месте. Ну и, собственно, работа с геозонами позволяет посылать сообщения, когда пользователь устройства входит в конкретную зону, покидает её либо находится в зоне определенный период времени.
На мой взгляд официальный пример довольно сложный и запутанный. Это связано с тем, что в нём:
- попытались показать все возможности Location APIs
- множество комментариев и обработок исключений, которые в примере можно было бы и упустить
- все действия выполняются из активити
Исходя из этого в данной статье я сфокусируюсь только на геозонах и опущу некоторые обработки исключений.
Примечание: Google Play сервисы могут быть отключены на устройстве. Это может нарушить работу многих приложений и система честно предупреждает пользователя об этом перед их отключением. Но всё же хорошим тоном будет проверять это в своем приложении с помощью GooglePlayServicesUtil.isGooglePlayServicesAvailable и как-то предупреждать пользователя.
Задача
Итак, для примера напишем приложение, в котором можно явно указать координаты и радиус геозоны. При входе/выходе из неё в статус бар будет добавляться уведомление с id геозоны и типом перемещения. После выхода из геозоны мы её удалим.
Алгоритм
В общем процесс выглядит следующим образом:
- Из активити создаем сервис, в который передаем данные о геозоне.
- Сервис инициализирует LocationClient.
- Когда LocationClient инициализировался, добавляем в него геозоны (Geofence) и соответствующие им PendingIntent.
- Когда геозоны добавлены, отключаемся от LocationClient и останавливаем сервис.
- Далее вся надежда на PendingIntent, который запустит IntentService при входе в зону или выходе из зоны. Сервис добавляет уведомления в статус бар и создает сервис для удаления отработанных геозон.
- Созданный сервис снова инициализирует LocationClient.
- Когда LocationClient инициализировался, удаляем отработанные геозоны.
- Когда геозоны удалены, отключаемся от LocationClient и останавливаем сервис.
- Profit!
Как мы видим, главным действующим лицом является LocationClient. Он отвечает за доступ к API для определения местоположения и работы с геозонами.
К делу!
Для начала необходимо подключить Google Play сервисы. Как это сделать описано здесь.
Далее в активити инициализируем элементы отображения. Из этой области нас интересует вызов сервиса при обработке нажатия на кнопку:
Тут мы создаем Intent для нашего сервиса (GeofencingService) и передаем в него необходимые данные. Так как GeofencingService отвечает за добавление и удаление геозон (в примере я решил не разделять эти действия на разные сервисы), то нам надо передать тип операции, которая должна быть выполнена сервисом. В данном случае это добавление (GeofencingService.Action.ADD). Также сервису нужны данные о геозоне. Их мы передаем в виде объекта класса MyGeofence, который по сути является оберткой над Geofence.Builder (о нём мы поговорим позже).
Итак, мы передаем координаты центра и радиус зоны, а также тип перемещения. Последний может быть трех видов: GEOFENCE_TRANSITION_ENTER, GEOFENCE_TRANSITION_EXIT и GEOFENCE_TRANSITION_DWELL. Если с первыми двумя все понятно, то к третьему необходимы разъяснения. GEOFENCE_TRANSITION_DWELL указывает на то, что пользователь вошел в зону и пробыл в ней некоторое время. Чтобы использовать этот сигнал, вы должны установить setLoiteringDelay при построении геозоны. В данном примере GEOFENCE_TRANSITION_DWELL не используется.
Перейдем к сервису. Сервис имплементирует GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener, LocationClient.OnAddGeofencesResultListener, LocationClient.OnRemoveGeofencesResultListener интерфейсы. Это позволяет ему полностью отвечать за работу с LocationClient.
В onStartCommand мы получаем тип операции (ADD или REMOVE) и вытягиваем необходимые для выполнения этого действия данные. После этого инициализируем и запускаем LocationClient:
Прежде чем добавить геозону mGeofenceListsToAdd, мы вызвали метод toGeofence() объекта класса MyGeofence. Я уже говорил, что MyGeofence является обёрткой над Geofence.Builder:
Geofence.Builder — это служебный класс для создания Geofence. Мы задаем необходимые параметры, а потом вызываем метод build() для создания объекта. Выше указан необходимый минимум параметров. Тут стоит обратить внимание на setExpirationDuration. Дело в том, что зарегистрированные геозоны могут быть удалены только в двух случаях: по истечении заданного времени или при явном удалении. Поэтому, если вы передаете в качестве параметра NEVER_EXPIRE, то вы обязаны позаботиться об удалении объекта самостоятельно. Для Location APIs есть ограничение: максимум 100 геозон на одно приложение одновременно.
После того как LocationClient подключится, сработает onConnected колбэк интерфейса GooglePlayServicesClient.ConnectionCallbacks. В нем мы выполняем добавление либо удаление в зависимости от текущего типа действия:
Как мы видим, addGeofences одним из параметров требует PendingIntent, который сработает при перемещении. В нашем случае PendingIntent будет запускать IntentService:
После выполнения действия у нас срабатывают OnAddGeofencesResultListener или onRemoveGeofencesByRequestIdsResult , в которых мы отключаемся от LocationClient и останавливаем сервис:
Последняя часть приложения – это IntentService, который запускается при пересечении границы геозоны пользователем устройства. Все действия выполняются в onHandleIntent:
Здесь у нас фигурируют в основном статические методы LocationClient. Сначала мы делаем проверку на наличие ошибок с помощью hasError. Затем получаем тип перемещения и список сработавших геозон с помощью getGeofenceTransition и getTriggeringGeofences соответственно. Вызываем обработку каждой геозоны и сохраняем её id. Ну и напоследок, удаляем геозоны в случае, если данное перемещение было выходом из геозоны.
Для удаления геозон мы опять создаём сервис, в который передаём тип операции (REMOVE) и список id на удаление:
На этом всё!
Надеюсь пример получился понятным и интересным. Желаю всем хороших приложений!
UPDATE:
Статья и код сильно устарели за 2 года.
Спасибо Vilkaman за обновления кода в репозитории.
Подробнее о работе с обновленным Location API можно прочитать в его статье
Источник
Geofencing in Android
Dec 7, 2017 · 4 min read
What is Geofence?
Geofencing is a location-based service that sends a notification to smartphone users who enter a defined geographic area. A geofence is a virtual barrier.
Some companies send promotions to customers’ smartphones when they enter a store, mall or neighborhood.
Geofencing combines awareness of the user’s current location with awareness of nearby features, defined as the user’s proximity to locations that may be of interest. To mark a location of interest, you specify its latitude and longitude. To adjust the proximity for the location, you add a radius. The latitude, longitude, and radius define a geofence. You can have multiple active geofences at one time.
To use geofencing, start by defining the geofences you want to monitor. Although you usually store geofence data in a local database or download it from the network, you need to send a geofence to Location Services as an instance of Geofence, which you create with Geofence.Builder . Each Geofence object contains the following information:
- Latitude, longitude, and radius
- Expiration time
- Transition type
- Geofence ID
First we need to provide the permissions in the AndroidManifest.
Geofencing needs Google Services API.
Open your build.gradle and add the dependency.
We have to check whether this device has Google Play Services Installed.
For getting the last known location, we could use GoogleServices API itself.
We are using Fused Location Api
Geofence Transitions
- GEOFENCE_TRANSITION_DWELL indicates that the user entered the area and spent some time there. It is useful to avoid multiple alerts when the user is entering and exiting the area too fast. You can configure the dwelling time using the setLoiteringDelay parameter.
- GEOFENCE_TRANSITION_ENTER indicates when the user enters the monitored region.
- GEOFENCE_TRANSITION_EXIT indicates when the user exits the region.
Create Geofencing Request and trigger
Create a class “GeofenceTransitionsIntentService” that extends IntentService.
When geofences required Re-register?
The app must re-register geofences if they’re still needed after the following events, since the system cannot recover the geofences in the following cases:
- The device is rebooted.
- The app is uninstalled and re-installed.
- The app’s data is cleared.
- Google Play services data is cleared.
- The app has received a GEOFENCE_NOT_AVAILABLE alert. This typically happens after NLP (Android’s Network Location Provider) is disabled.
Источник
How to Work With Geofences on Android
Location aware resources allow your application to interact with the physical world and they are ideal for increasing user engagement. Although many mobile apps use them, the topic of this tutorial is a feature that is often overlooked, geofencing.
A geofence is a virtual perimeter set on a real geographic area. Combining a user position with a geofence perimeter, it is possible to know if the user is inside or outside the geofence or even if he is exiting or entering the area.
Imagine a university app that can tell you which colleagues and professors are currently on campus. Or an app for a mall that rewards regular customers. There are many other interesting possibilities that you can explore.
In this tutorial, you learn how to use geofences on Android by creating an application that shows the user a notification when they enter or exit a geofence. It helps if you have previous knowledge of Google Play Services, the Google Maps Android API, or IntentService . If you don’t, then you can still follow along, but you may want to do some research about these topics after reading this tutorial.
1. Geofences on Android
On Android, there are several ways to work with geofences. You could even create your own implementation to work with geofences, but it is easier to use Google’s GeofencingApi .
This APIs is part of Google’s Location APIs. It includes Geofence , GeofencingRequest , GeofenceApi , GeofencingEvent , and GeofenceStatusCodes . In this tutorial, we use these classes to create and work with geofences.
Geofence Interface
Geofence is an interface that represents a geographical area that should be monitored. It is created by using the Geofence.Builder . During its creation, you set the monitored region, the geofence’s expiration date, responsiveness, an identifier, and the kind of transitions that it should be looking for.
To keep power consumption to a minimum, it is recommended to use a geofence with a radius of at least 100 meters for most situations. If geofences are located in the countryside, you should increase the radius to 500 meters or higher to make sure the geofences are effective.
Geofence Transitions
- GEOFENCE_TRANSITION_DWELL indicates that the user entered the area and spent some time there. It is useful to avoid multiple alerts when the user is entering and exiting the area too fast. You can configure the dwelling time using the setLoiteringDelay parameter.
- GEOFENCE_TRANSITION_ENTER indicates when the user enters the monitored region.
- GEOFENCE_TRANSITION_EXIT indicates when the user exits the region.
GeofenceRequest
The GeofencingRequest class receives the geofences that should be monitored. You can create an instance by using a Builder , passing a Geofence or a List , and the kind of notification to trigger when the geofence(s) is created.
GeofencingApi
The GeofencingApi class is the entry point for all interactions with Google’s geofencing API. It is part of the Location APIs and it depends on a GoogleApiClient to work. You will use the GeofencingApi to add and remove geofences.
To add a geofence, you call the addGeofence() method. It monitors the given area using the settings passed to the GeofencingRequest and shoots a PendingIntent when a geofence transition, entering or exiting the area, takes place.
To remove the geofence, you call removeGeofences() . You can either remove the geofence using its request identifier or its pending intent.
2. Creating a Geofencing App
In this tutorial, we create a simple application that monitors the user location and posts a notification when the user enters or exits a geofenced area. The app consists of only one Activity and an IntentService . We also take a quick look at GoogleMap , GoogleApiClient , and FusedLocationProviderApi , and we explore some caveats of the geofence API.
Step 1: Project Setup
GeofencingApi is part of Google Play Services. To access it, you need to correctly set up your development environment and create an instance of the GoogleApiClient . Create a new project with a blank Activity , edit the project’s build.gradle file as shown below, and synchronize your project.
Step 2: Permissions
We need to set the correct permissions to create and use geofences. Add the following permission to the project’s manifest:
Starting with Android 6.0, the app asks for permission at run time and not during the installation. We address this later in the tutorial.
Step 3: Creating the Layout
The project consists of one layout, the MainActity layout. It contains the device’s current latitude and longitude, and a GoogleMap fragment that displays the geofences and the user’s position.
Since activity_main.xml is pretty straightforward, I want to concentrate only on the MapFragment element. You can take a look at the completed layout in the source files of this tutorial.
Step 4: Google Maps API Key
Since we are using a MapFragment , we need to set up and initialize a GoogleMap instance. First, you need to obtain an API key. Once you have an API key, add it to the project’s manifest.
Let’s begin with the GoogleMap instance. Implement GoogleMap.OnMapReadyCallback , GoogleMap.OnMapClickListener , and GoogleMap.OnMarkerClickListener in the Activity class and initialize the map.
Step 5: GoogleApiClient
To use the GeofencingApi interface, we need a GoogleApiClient entry point. Let’s implement a GoogleApiClient.ConnectionCallbacks and a GoogleApiClient.OnConnectionFailedListener in the Activity as shown below.
Step 6: FusedLocationProviderApi
We also need to access the user’s current location. The FusedLocationProviderApi interface gives us this information and allows a great level of control of the location request. This is very important, considering that location requests have a direct effect over the device’s battery consumption.
Now, let’s implement a LocationListener . Check if the user gave the application the appropriate permissions by creating the Location request and display their the current location on the screen.
It is important to address that the LocationRequest created above isn’t optimized for a production environment. The UPDATE_INTERVAL is too short and would consume too much battery power. A more realistic configuration for production could be:
Step 7: GoogleMap Markers
Our Activity needs two different markers. A locationMarker uses the latitude and longitude given by the FusedLocationProviderApi to inform the device’s current location. A geoFenceMarker is the target for the geofence creation as it uses the last touch given on the map to retrieve its position.
Step 8: Creating a Geofence
At last, it is time to create a geofence. We use the geoFenceMarker as the center point for the geofence.
Next, we create the GeofencingRequest object.
We use a PendingIntent object to call a IntentService that will handle the GeofenceEvent . We create the GeofenceTrasitionService.class later.
We also draw the geofence on the map as a visual reference.
The startGeofence() method is responsible for starting the geofencing process in the MainActivity class.
Step 9: Geofence Transition Service
We can now finally create the GeofenceTrasitionService.class mentioned earlier. This class extends IntentService and is responsible for handling the GeofencingEvent . First, we get this event from the received intent.
We then check if the kind of geofencing transition that took place is of interest to us. If it is, we retrieve a list of the triggered geofences and create a notification with the appropriate actions.
I have also implemented a few helper methods to make the implementation of the class easier to understand.
3. Testing
Testing on a Virtual Device
It is much simpler to test geofencing on a virtual device. There are several ways to do this. In Android Studio, open a virtual device and click the more options button in the bottom right.
In the Location tab on the left, enter the coordinates for the location.
I prefer to use telnet commands to control the virtual device. To use this, you need to connect to the device from the command line using the following command:
The device port is shown in the virtual device window. The device port is usually equal to 5554.
It is possible that you need to authorize this connection using your auth_token , but the command line shows you where it is located. Navigate to that location and copy the token and type, auth [YOUR_AUTH_TOKEN] .
You can now set the location of the device by running the following command:
Conclusion
Geofencing may be a great addition to your app as it can considerably increase user engagement. There are lots of possibilities to explore and you could even create a sophisticated experience using indoor beacons, such as the Estimote. With indoor beacons, you know exactly where the user has passed in, for example, a shopping mall.
Adding Geofencing to a project is simple, but we need to keep power consumption in mind at all times. This means that we need to carefully choose the size of the geofence and the update rate because both directly impact power consumption of your application.
Testing is therefore very important to get a realistic idea of the power consumption of your application. Also consider giving users the option to disable geofencing altogether if they don’t want or need this feature.
Источник