Monitor POIs with Geofence
Monitor POIs with Geofence using Flutter Plugin
Create and monitor Geofences
Use region monitoring to determine when the user enters or leaves a geographic region.
Region monitoring (also known as Geofencing) combines awareness of the user’s current location with awareness of the user’s proximity to locations that may be of interest. This region alerts your app when the user enters or exits a geographical region. 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, creating a circular area, or fence, around the location of interest. Find more details about Geofences in Geofence documentation
Adding and removing regions
Call addRegion method to add a region you want to monitor. Region type can be circle or isochrone only. This method will accept an object with following attributes:
- regionId - Id of the region
- lat - Latitude
- lng - Longitude
- radius - Radius in meters
- type - type of region
Create a custom circle region
GeofenceRegion geofenceRegion = GeofenceRegion(
'7F91369E-467C-4CBD-8D41-6509815C4780',
51.50998,
-0.1337,
180,
RegionType.circle
);
Future<String?> returnVal = geofencingFlutterPlugin.addRegion(geofenceRegion);
returnVal.then((value){
debugPrint(value!);
}).catchError((error) {
debugPrint('An error occurred: ${error.message}');
});
Create a custom isochrone region
GeofenceRegion geofenceRegion = GeofenceRegion(
'7F91369E-467C-4CBD-8D41-6509815C4780',
51.50998,
-0.1337,
180,
RegionType.isochrone
);
Future<String?> returnVal = geofencingFlutterPlugin.addRegion(geofenceRegion);
returnVal.then((value){
debugPrint(value!);
}).catchError((error) {
debugPrint('An error occurred: ${error.message}');
});
Remove regions
Call removeRegions method to remove a region that you are monitoring. This method will accept the following parameter, and passing a null value will remove all regions.
- regionId - Id of the region
- lat - Latitude
- lng - Longitude
- radius - Radius in meters
Future<String?> returnVal = geofencingFlutterPlugin.removeRegions('7F91369E-467C-4CBD-8D41-6509815C4780');
returnVal.then((value){
debugPrint(value!);
}).catchError((error) {
debugPrint('An error occurred: ${error.message}');
});
or
Future<String?> returnVal = geofencingFlutterPlugin.removeRegions();
returnVal.then((value){
debugPrint(value!);
}).catchError((error) {
debugPrint('An error occurred: ${error.message}');
});
Whenever user crosses boundary of one of your app’s registered regions, the system notifies your app.
On object Region, there is a boolean didEnter that indicates if you enter or exit region. You have
another boolean fromPositionDetection to know if the detection was launched by the position detection or by the system
detection.
Regions have an associated identifier, which this method uses to look up information related to region and perform associated action.
Get regions from the local database
Call getRegions method to get an array of Regions from local db.
//Get a single region
Future<List<Region>?> returnVal = geofencingFlutterPlugin.getRegions(regionId);
returnVal.then((regions){
if (regions != null){
debugPrint('Regions: ${regions.length}');
}else{
debugPrint('Regions is null');
}
}).catchError((error) {
debugPrint('An error occurred: ${error.message}');
});
//Get all regions
Future<List<Region>?> returnVal = geofencingFlutterPlugin.getRegions();
returnVal.then((regions){
if (regions != null){
debugPrint('Regions: ${regions.length}');
}else{
debugPrint('Regions is null');
}
}).catchError((error) {
debugPrint('An error occurred: ${error.message}');
});
Watch Region to track the region’s events
Call watchRegions method to track Regions. This method will invoke a callback with the Region object.
Future<String?> returnVal = geofencingFlutterPlugin.watchRegion();
returnVal.then((value){
//Get the region stream
watchRegionStream = geofencingFlutterPlugin.getWatchRegionStream();
//Listen to the stream
watchRegionStream.listen((region){
//Region updates will be received here.
if (location != null) {
debugPrint(region.eventName);
} else {
debugPrint("Region is null");
}
});
}).catchError((error) {
debugPrint('An error occurred: $error');
});
To remove watch:
Future<String?> returnVal = geofencingFlutterPlugin.clearRegionWatch();
returnVal.then((value){
debugPrint(value!);
}).catchError((error) {
debugPrint('An error occurred: $error');
});
Background region events (application in the background or terminated)
getWatchRegionStream only delivers events while a Flutter engine of the application is running. To handle region events after the application has been terminated, register a Dart callback with registerBackgroundRegionCallback. The plugin starts a headless Flutter engine and invokes that callback in a background isolate.
The callback and the plugin entry point must survive tree shaking, so the callback has to be a top level or static function annotated with @pragma('vm:entry-point'):
import 'package:flutter/foundation.dart';
import 'package:geofencing_flutter_plugin/geofencing_flutter_plugin.dart';
@pragma('vm:entry-point')
void onBackgroundRegionEvent(Region region) {
// Runs in a background isolate, without the widget tree.
debugPrint('${region.eventName} on ${region.identifier}');
}
// Register it once, for instance right after initialize():
Future<bool> registered =
geofencingFlutterPlugin.registerBackgroundRegionCallback(onBackgroundRegionEvent);
To stop waking a background isolate:
Future<bool> removed = geofencingFlutterPlugin.unregisterBackgroundRegionCallback();
stopTracking() removes the callback as well: tracking is what produces region events, so nothing is left that could wake a background isolate. Register the callback again after the next startTracking() call.
To know whether a callback is currently registered, for instance to restore it at startup:
if (!await geofencingFlutterPlugin.hasBackgroundRegionCallback()) {
await geofencingFlutterPlugin.registerBackgroundRegionCallback(onBackgroundRegionEvent);
}
The registration is persisted natively, so hasBackgroundRegionCallback() stays accurate after the application has been restarted.
The callback receives the same Region object as the region stream, with the same fields on both platforms. It is invoked only when no Dart listener is consuming the region stream: while the application is running and listening with getWatchRegionStream, events go to the stream only, so an event is never handled twice.
Background location permission (GRANTED_BACKGROUND) is required on both platforms.
Constraints of the background isolate
- No shared memory. The background isolate shares nothing with the UI isolate: singletons, global variables, providers and any application state are not available there. Only self contained logic transfers as is (pure functions, HTTP calls, local database, local notifications).
- Plugin registration. Other plugins must be registered in that isolate. On Android this is automatic. On iOS, add the registrant to your
AppDelegate(see below). - Keep it short. Both platforms run the callback on a limited background budget, and long running work risks being terminated by the system.
On iOS, register the plugins for the background isolate in your AppDelegate:
import geofencing_flutter_plugin
GeofencingFlutterPlugin.setPluginRegistrantCallback { registry in
GeneratedPluginRegistrant.register(with: registry)
}
iOS: the operating system relaunches the application for the region event. The plugin restarts the Woosmap service with the key and tracking profile of the previous run, then runs the callback within a background task.
Android: the event is delivered by the Woosmap SDK broadcast, which starts the process when needed, for instance after the application was swiped away from the recent apps or its process was reclaimed by the system.
On Android, a force-stopped application (Settings > Force stop, or adb shell am force-stop) cannot be woken: Android cancels its geofence triggers and nothing is delivered until the user opens it again. Some manufacturers treat swiping the application away as a force stop when battery optimisation is enabled for it.
Create regions from Woosmap Search API assets
Region monitoring is a natural complement to Search requests performed on collected locations. Indeed, Search requests help monitor approach to some assets you want to monitor. On every collected location you are aware of surrounding assets (distance to them and even time if using Distance API request). You can then decide to monitor some surrounding assets (e.g. the closest ones). Region monitoring is designed to do so.
To create a region around nearest result of the Search API request, choose a tracking profile with the tracking
properties searchAPICreationRegionEnable enable.
Pre-requisites
You must define a Woosmap private API key to request the Woosmap Search API. How to set an Woosmap private key is explained
in
the Initializing the plugin section.