Flutter Background Geofencing

pub package popularity likes pub points

A Flutter plugin for native background geofencing with battery-efficient hardware-assisted location monitoring on Android and iOS.

Features

Native Platform APIs - Android: GeofencingClient (API 19+), iOS: CLLocationManager (iOS 4.0+)
Background Support - True background monitoring with foreground service (Android) and region monitoring (iOS)
Battery Efficient - Uses hardware-assisted geofencing APIs, no continuous location polling
Event-driven Architecture - Clean separation: plugin provides events, your app handles business logic
Fallback Notifications - Native notifications when Flutter app is killed
Dynamic Configuration - Runtime control over notifications and monitoring settings

Installation

Add this to your package's pubspec.yaml file:

dependencies:
  flutter_background_geofencing: ^1.0.0

Then run:

flutter pub get

Platform Setup

Android

Add permissions to android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />

Set minSdkVersion to 19 or higher in android/app/build.gradle:

android {
    defaultConfig {
        minSdkVersion 19
    }
}

iOS

Add location permissions to ios/Runner/Info.plist:

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs location access for geofencing</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs location access for geofencing</string>

Usage

Basic Setup

import 'package:flutter_background_geofencing/flutter_background_geofencing.dart';

class LocationService {
  final GeofencingService _service = GeofencingService();

  Future<void> initialize() async {
    // 1. Initialize
    await _service.initialize();
    
    // 2. Request permissions  
    await _service.requestPermissions();
    
    // 3. Start background service
    await _service.startService(
      notificationTitle: 'Location Monitoring',
      notificationText: 'Monitoring geofence regions',
    );
    
    // 4. Listen for events
    _service.onGeofenceEvent.listen(_handleGeofenceEvent);
  }
  
  void _handleGeofenceEvent(GeofenceEvent event) {
    if (event.type == GeofenceEventType.enter) {
      // Handle entry - show notification, trigger action, etc.
      print('Entered region: ${event.regionId}');
    }
  }
}

Adding Geofence Regions

// Add a circular geofence region
final region = GeofenceRegion(
  id: 'office',
  latitude: 37.7749,
  longitude: -122.4194,
  radius: 100.0, // meters
  data: {'name': 'Office Location'},
);

await _service.addGeofence(region);

Fallback Notifications (App Killed)

// Configure fallback notifications for when app is killed
await _service.startService(
  notificationTitle: 'Location Monitoring',
  notificationText: 'Monitoring regions',
  enableFallbackNotifications: true,
  fallbackNotificationTitle: 'Location Alert',
  fallbackNotificationBody: 'You entered {regionName}',
);

API Reference

GeofencingService

Main service class for geofencing functionality.

Method Description
initialize() Initialize the service
startService() Start background monitoring
stopService() Stop monitoring
addGeofence(region) Add a geofence region
removeGeofence(id) Remove a region by ID
requestPermissions() Request location permissions

GeofenceRegion

Represents a circular geofence region.

GeofenceRegion({
  required String id,           // Unique identifier
  required double latitude,     // Center latitude
  required double longitude,    // Center longitude  
  required double radius,       // Radius in meters
  Map<String, dynamic>? data,   // Custom data
})

GeofenceEvent

Event triggered when crossing geofence boundaries.

class GeofenceEvent {
  final GeofenceEventType type;     // enter, exit, dwell
  final String regionId;            // Region identifier
  final DateTime timestamp;        // Event time
  final GeofenceLocation? location; // Triggering location
}

Platform Limitations

Platform Max Regions Min Radius Background Requirement
Android 100 100m (recommended) ACCESS_BACKGROUND_LOCATION (API 29+)
iOS 20 1m (100m+ recommended) "Always" location authorization

Troubleshooting

Common Issues

Geofences not triggering:

  • Ensure proper location permissions (Always/Background)
  • Use minimum 100m radius for reliability
  • Test with realistic movement (not simulator location changes)

Service stops on Android:

  • Disable battery optimization for your app
  • Ensure foreground service notification isn't dismissed

iOS background limitations:

  • Enable Background App Refresh
  • iOS may delay events for battery conservation

Permission Handling

Android API 29+: Request in two steps:

  1. First: ACCESS_FINE_LOCATION
  2. Then: ACCESS_BACKGROUND_LOCATION

iOS: Always request "Always" authorization for geofencing.

Example

See the example directory for a complete implementation.

License

This project is licensed under the MIT License - see the LICENSE file for details.