Skip to Content
DevelopersSDKsFlutter SDKGeofencing & location

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