Geofencing & location
The Active Reach Flutter SDK (active_reach_sdk) can monitor a set of geofences — typically derived from an operator’s outlet table — and emit entry/exit events your app can act on. The Dart bridge talks to native iOS CoreLocation (which transparently handles the platform’s 20-region cap via a nearest-N strategy) and Android Play Services geofencing (no region cap).
Geofencing is opt-in. The Active Reach SDK does not request location permission and declares no location permission of its own — so apps that never call startMonitoring get no location prompt. When you do use geofencing, your host app owns the entire permission lifecycle: declaring the platform permissions and requesting them at runtime before monitoring starts.
Permissions are host-owned
The SDK will start monitoring whatever geofences you pass, but it relies on your app having already obtained location permission. You must do two things yourself.
Declare platform permissions
iOS — add usage descriptions to Info.plist:
<key>NSLocationWhenInUseUsageDescription</key>
<string>We use your location to notify you about offers near our outlets.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>We use your location to notify you about offers near our outlets.</string>Android — add to your app’s AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Required for background geofencing on API 29+ -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />Request permission at runtime
Use your app’s preferred permissions plugin to request location access from the user before you start monitoring. The Active Reach SDK does not prompt on your behalf.
Start monitoring your outlet geofences
import 'package:active_reach_sdk/active_reach_sdk.dart';
await AegisLocation.instance.startMonitoring([
const Geofence(
id: 'outlet_mg_road',
label: 'MG Road',
latitude: 12.9756,
longitude: 77.6068,
radiusMeters: 150,
metadata: {'outlet_code': 'BLR-01'},
),
const Geofence(
id: 'outlet_indiranagar',
label: 'Indiranagar',
latitude: 12.9719,
longitude: 77.6412,
// radiusMeters defaults to 100 when omitted
),
]);Subscribe to entry/exit events
import 'dart:async';
import 'package:active_reach_sdk/active_reach_sdk.dart';
StreamSubscription<GeofenceEvent>? _geoSub;
void startListening() {
_geoSub = AegisLocation.instance.onEvent((event) {
if (event.eventName == GeofenceEventName.entered) {
print('Entered ${event.geofenceLabel} (${event.geofenceId})');
} else {
print('Exited ${event.geofenceLabel}');
}
});
}Stop monitoring on logout / opt-out
await AegisLocation.instance.stopMonitoring();
_geoSub?.cancel();API reference
Geofence
class Geofence {
final String id;
final String label;
final double latitude;
final double longitude;
final double radiusMeters; // defaults to 100
final Map<String, String>? metadata;
}Geofence exposes toMap(), which the SDK uses to bridge each region to the native side.
AegisLocation
Access the singleton via AegisLocation.instance:
Future<void> startMonitoring(List<Geofence> geofences)— configure the set of regions to monitor.Future<void> stopMonitoring()— stop monitoring all geofences. Call on logout / opt-out.StreamSubscription<GeofenceEvent> onEvent(void Function(GeofenceEvent) callback)— subscribe to entry/exit events; call.cancel()to unsubscribe.
GeofenceEvent
class GeofenceEvent {
final GeofenceEventName eventName; // entered | exited
final String geofenceId;
final String geofenceLabel;
final double geofenceLatitude;
final double geofenceLongitude;
final double geofenceRadiusMeters;
final Map<String, String> metadata;
}GeofenceEventName has two values: entered (wire geofence.entered) and exited (wire geofence.exited).
Platform channels
The bridge uses two channels, both already wired by the SDK:
MethodChannel('active_reach_sdk/location')—startMonitoring,stopMonitoring.EventChannel('active_reach_sdk/geofence_events')— the entry/exit event stream.
Native iOS CoreLocation re-sorts the nearest 20 regions on significant-location-change updates, so you can pass more than 20 geofences and the closest ones stay active transparently. Android Play Services has no such cap.
What’s next
- Flutter SDK reference — install, init, and core tracking
- Event ingestion — how SDK signals reach the platform