smart_location 3.0.2
smart_location: ^3.0.2 copied to clipboard
Smart Location is a powerful, battery-conscious Flutter plugin for continuous background geolocation tracking, advanced geofencing, and motion-aware updates.
Smart Location #
[Demo]
A developer-friendly, DX-first Flutter package for handling location. It internally wraps native OS location APIs with a clean, top-down designed interface that minimizes boilerplate and implements advanced client-side algorithms out of the box.
🤔 Why use smart_location over geolocator? #
- Zero Battery Drain Batched Syncing: Native integration with Android
WorkManagerand iOSBGTaskSchedulerallows for headless, batched coordinate syncing without keeping the Dart VM alive. - WebAssembly (WASM) Support: Fully compatible with Flutter Web WASM compilation.
- True Native Background Services Built-in: Includes out-of-the-box support for Android Foreground Services to ensure your app tracks continuously even when swiped away.
- Offline Persistence: Automatically saves locations locally if the network drops and syncs them when reconnected.
Features #
🌟 Core Capabilities #
- One-line Location Fetching: Get the current location safely.
- Continuous Tracking: Listen to location stream with simple configurations.
- Smart Permission Handling: Checks GPS and prompts permissions automatically.
- Pure Dart Models: Safe mapping from raw platform data to clean Dart classes.
🚀 Advanced Capabilities (New!) #
- Client-Side Geofencing (Spatial Hash Optimized): Monitor geofences with entry, exit, and dwell triggers. Optimized with an $O(1)$ Spatial Hashing grid to support hundreds of fences without performance degradation.
- Route Recorder & Compressors: Record paths with real-time stats. Compress routes using the Ramer-Douglas-Peucker (RDP) algorithm, export to Google Encoded Polyline format, or generate standard GeoJSON outputs.
- Driver Safety (Speed & G-Force Monitor): Detect speed limit violations and identify sudden braking or acceleration events.
- Privacy Guard: Fuzz location coordinates within a randomized radius or snap to a coarse grid resolution to safeguard user privacy.
- Dead Reckoning Kinematic Engine: Extrapolate coordinates automatically using bearing and speed vector kinematics when GPS signals drop.
- Battery & Network Eco-Optimizer: Recommend adaptive tracking configurations to prolong device battery life.
- Anti-Spoofing & Fake GPS Engine: Automatically detects and filters mock locations, rooting apps, and physically impossible "teleportation" speed jumps. Ideal for ride-sharing and delivery tracking.
- Route Deviation & Off-Route Detection: Emits alerts when a driver veers off their prescribed route by a configurable threshold.
- Multi-Stop Journey Manager: Automates tracking progress along a multi-stop delivery or ride sequence, auto-advancing as waypoints are reached.
- Live Streaming Adapter: Exposes an adapter to seamlessly push GPS streams directly to WebSockets or MQTT publishers at controlled rates.
- OS Health Monitor: Continuously watches for silent OS permission downgrades or battery saver mode activations.
- Severe Crash Detector: Identifies violent vehicular impacts by analyzing extreme G-force deceleration.
- Indoor WiFi Centroid Locator: Estimate indoor coordinates by calculating a weighted centroid from surrounding access point RSSI strengths.
Getting Started #
Add the dependency to your pubspec.yaml:
dependencies:
smart_location: ^3.0.2
🔥 Feature Spotlight: Headless Batched Sync #
Unlike basic location wrappers that die when the app is swiped away, smart_location acts as a true enterprise tracking engine:
- Unkillable Tracking: It natively binds to Android Foreground Services and iOS Background Tasks to track forever.
- Offline Resilience: If the user enters a tunnel, locations are seamlessly saved to an offline SQLite database.
- Battery-Optimized Headless Sync: Waking up the Dart VM constantly drains batteries.
smart_locationuses AndroidWorkManagerand AppleBGTaskSchedulerto wake up a hidden Dart Isolate once every 15 minutes. You register a Dart callback, we wake it up, and you bulk-upload your offline coordinates to Firebase or your REST API seamlessly!
Platform Setup #
Android #
In android/app/src/main/AndroidManifest.xml, add inside <manifest>:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
Background Location (optional):
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
iOS #
In ios/Runner/Info.plist, add:
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs location access to provide better services.</string>
Background Location (optional):
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs location access for background tracking.</string>
Background Sync (required for Headless Batching):
In ios/Runner/Info.plist, you must register the background task identifier:
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>com.antigravity.smart_location.sync</string>
</array>
<key>UIBackgroundModes</key>
<array>
<string>location</string>
<string>fetch</string>
<string>processing</string>
</array>
API Overview #
Primary Methods #
| API | Purpose |
|---|---|
SmartLocation.ensureReady() |
Request permission + verify GPS is on |
SmartLocation.current() |
One-time location fetch |
SmartLocation.lastKnown() |
Last cached location (no GPS needed) |
SmartLocation.stream |
Continuous live updates |
SmartLocation.streamWithSettings(...) |
Live updates with custom accuracy/filter |
SmartLocation.distanceBetween(...) |
Distance in meters between two points |
SmartLocation.bearingBetween(...) |
Direction/heading between two points |
SmartLocation.simplifyPath(...) |
Simplifies a list of coordinates using RDP |
Advanced Sub-Managers #
| Sub-Manager | Class | Purpose |
|---|---|---|
SmartLocation.geofence |
GeofenceManager |
Client-side geofencing monitoring |
SmartLocation.recorder |
RouteRecorder |
Path recording & live session stats |
SmartLocation.speed |
SpeedMonitor |
Driver safety monitor (speeding, braking alerts) |
SmartLocation.privacy |
PrivacyGuard |
Coordinate fuzzer and snapped grid utilities |
SmartLocation.deadReckoning |
DeadReckoning |
Extrapolator watchdog during GPS signal drops |
SmartLocation.matching |
MapMatching |
Path smoothing & road segment snapping |
SmartLocation.eco |
EcoOptimizer |
Adaptive accuracy & distance configuration helper |
SmartLocation.indoor |
IndoorEmulator |
WiFi / Bluetooth beacon RSSI centroid tracking |
SmartLocation.antiSpoofing |
AntiSpoofingEngine |
Teleportation & OS-level mock location filter |
SmartLocation.deviation |
OffRouteDetector |
Route deviation and off-route detection monitor |
SmartLocation.liveStream |
LiveStreamingAdapter |
WebSockets / MQTT live tracking publisher adapter |
SmartLocation.journey |
JourneyManager |
Multi-stop delivery tracking sequence auto-advancer |
SmartLocation.health |
OSHealthMonitor |
Background permission and battery saver degradation watcher |
SmartLocation.crash |
CrashDetector |
Severe vehicular impact / G-force deceleration monitor |
Usage #
1. Initialize & Ensure Permissions #
import 'package:smart_location/smart_location.dart';
// Checks GPS status and requests location permission from the user
await SmartLocation.ensureReady();
2. Get Current Location #
try {
final loc = await SmartLocation.current();
print('Location: ${loc.latitude}, ${loc.longitude}');
} on LocationDisabledException {
print('Please turn on GPS');
} on PermissionDeniedException {
print('Permission was denied');
}
3. Listen to Location Stream #
SmartLocation.stream.listen((loc) {
print('Moving to: ${loc.latitude}, ${loc.longitude}');
});
Advanced Features Usage #
1️⃣ Client-Side Geofencing (Spatial Hash Optimized) #
Efficiently monitors multiple circular geofences using a spatial grid. Emits transition events when entering, exiting, or dwelling in a zone.
// 1. Create a geofence with enter, exit, and dwell triggers
final geofence = Geofence(
id: 'office_HQ',
latitude: 37.7749,
longitude: -122.4194,
radiusInMeters: 100.0,
triggerTypes: {GeofenceTrigger.enter, GeofenceTrigger.exit, GeofenceTrigger.dwell},
dwellDuration: const Duration(minutes: 5),
);
// 2. Register and start monitoring
SmartLocation.geofence.addGeofence(geofence);
SmartLocation.geofence.startMonitoring(SmartLocation.stream);
// 3. Listen to transition events
SmartLocation.geofence.events.listen((event) {
print('Geofence Event [${event.geofenceId}]: ${event.triggerType}');
});
2️⃣ Route Recorder & Compression Utilities #
Record user journeys, gather statistics (duration, distance, coordinates count), and format paths for mapping and storage optimization.
// Start recording the route
SmartLocation.recorder.start(SmartLocation.stream);
// Read live session statistics
print('Recorded Distance: ${SmartLocation.recorder.totalDistanceInMeters} m');
print('Elapsed Time: ${SmartLocation.recorder.elapsedTime}');
// Stop recording and retrieve path coordinates
final List<LocationData> path = SmartLocation.recorder.stop();
// Simplify the route path to reduce storage size (Ramer-Douglas-Peucker algorithm)
final List<LocationData> simplified = SmartLocation.simplifyPath(path, 10.0); // 10m tolerance
// Convert path to Google Encoded Polyline format
final String polyline = SmartLocation.maps.encodePolyline(simplified);
// Export coordinates to standard GeoJSON maps
final Map<String, dynamic> pointGeoJson = GeoJsonExporter.toPointMap(path.last);
final Map<String, dynamic> lineGeoJson = GeoJsonExporter.toLineStringMap(simplified);
3️⃣ Driver Safety Monitor (Speeding & Sudden G-Force Events) #
Evaluates speed thresholds and detects sudden acceleration or harsh braking rates.
// Configure limits: speed limit and deceleration/acceleration rates
SmartLocation.speed.configure(
speedLimitKmh: 80.0,
suddenDecelThresholdKmhPerSec: 15.0, // harsh brake threshold
suddenAccelThresholdKmhPerSec: 10.0, // harsh acceleration threshold
);
// Start monitoring the GPS stream
SmartLocation.speed.startMonitoring(SmartLocation.stream);
// Receive alerts
SmartLocation.speed.speedAlerts.listen((alert) {
print('Speed Warning: ${alert.message}'); // Speed limit exceeded
});
SmartLocation.speed.gForceAlerts.listen((alert) {
print('G-Force Warning: ${alert.message}'); // Harsh braking or acceleration
});
4️⃣ Privacy Guard (Location Obfuscation) #
Protects user identity and location patterns by adding a random displacement radius or snapping coordinates to a coarse degrees grid resolution.
final LocationData rawLocation = await SmartLocation.current();
// 1. Fuzz: Offset coordinates randomly within a 500-meter radius
final LocationData fuzzedLocation = PrivacyGuard.fuzz(rawLocation, radiusInMeters: 500.0);
// 2. Snap to Grid: Snaps coordinates to the nearest degree intersection (e.g. 0.01 degrees)
final LocationData snappedLocation = PrivacyGuard.snapToGrid(rawLocation, gridSizeDegrees: 0.01);
5️⃣ Dead Reckoning Fallback Engine #
Keeps navigation UI fluent and responsive during GPS drops or indoor transitions by automatically extrapolating coordinates based on previous velocity and bearing heading vectors.
// Start the dead reckoning engine
SmartLocation.deadReckoning.start(
gpsStream: SmartLocation.stream,
onUpdate: (location) {
if (location.isMocked) {
print('Extrapolated Position: ${location.latitude}, ${location.longitude}');
} else {
print('GPS Raw Position: ${location.latitude}, ${location.longitude}');
}
},
staleThreshold: const Duration(seconds: 3), // triggers DR when GPS is stale for 3 seconds
extrapolationInterval: const Duration(seconds: 1),
);
// Stop engine when done
SmartLocation.deadReckoning.stop();
6️⃣ Battery & Network Eco-Optimizer #
Implements power-saving strategies adaptively based on battery percent levels and connectivity states.
// Query optimal configuration recommendations
final LocationAccuracy accuracy = SmartLocation.eco.getOptimizedAccuracy(
batteryLevelPercent: 25.0,
hasNetwork: true,
);
final int filter = SmartLocation.eco.getOptimizedDistanceFilter(
batteryLevelPercent: 25.0,
hasNetwork: true,
);
// Listen to stream using recommended eco configurations
final ecoStream = SmartLocation.streamWithSettings(
accuracy: accuracy,
distanceFilter: filter,
);
7️⃣ Indoor WiFi / Beacon Centroid Locator #
Calculates the device position indoors using the weighted average signal strengths of surrounding beacons or Wi-Fi access points.
// 1. Register indoor beacon/Wi-Fi locations
SmartLocation.indoor.registerBeacons({
'Lobby_AP': LocationData(latitude: 37.774900, longitude: -122.419400, accuracy: 2.0, altitude: 0, speed: 0, speedAccuracy: 0, heading: 0),
'ConfRoom_AP': LocationData(latitude: 37.775200, longitude: -122.419000, accuracy: 3.0, altitude: 0, speed: 0, speedAccuracy: 0, heading: 0),
});
// 2. Estimate position based on scanned signal levels (dBm RSSI)
final LocationData? estimatedLocation = SmartLocation.indoor.locateBySignals({
'Lobby_AP': -40.0,
'ConfRoom_AP': -90.0,
});
8️⃣ Anti-Spoofing & Fake GPS Detection Engine (New!) #
Crucial for ride-sharing and delivery logistics. By default, SmartLocation.stream uses aggressive filtering and automatically drops spoofed coordinates. It detects mock flags and impossible teleportation jumps.
// Listen to spoofing alerts to warn the user or flag their account internally
SmartLocation.antiSpoofing.alerts.listen((alert) {
print('Spoofing Detected: ${alert.reason}'); // "OS marked as mock" or "Teleportation detected"
});
// If you prefer to allow fake locations through the stream (e.g. for debug mode):
SmartLocation.antiSpoofing.isAggressiveFilteringEnabled = false;
9️⃣ Route Deviation & Off-Route Detection #
Crucial for ride-sharing safety and delivery tracking. Pass an expected route to the SDK, and it will emit alerts if the driver veers too far off course.
// Set the expected route (list of LocationData coordinates)
SmartLocation.deviation.expectedRoute = [
LocationData(latitude: 37.7749, longitude: -122.4194, /* ... */),
LocationData(latitude: 37.7750, longitude: -122.4180, /* ... */),
];
// Configure how far they can deviate before triggering an alert (e.g., 50 meters)
SmartLocation.deviation.deviationThresholdMeters = 50.0;
// Start monitoring against the live GPS stream
SmartLocation.deviation.startMonitoring(SmartLocation.stream);
// Listen to deviations
SmartLocation.deviation.alerts.listen((event) {
print('Driver is OFF ROUTE! Deviated by ${event.deviationDistanceMeters}m');
});
🔟 Ultimate Enterprise Modules #
For bleeding-edge ride-sharing and logistics, we offer these 4 advanced modules out of the box:
// 1. Live Streaming Adapter (WebSockets / MQTT)
SmartLocation.liveStream.startStreaming(
gpsStream: SmartLocation.stream,
publisher: (location) => myWebSocket.sink.add(location.toJson()),
);
// 2. Multi-Stop Journey Manager
SmartLocation.journey.startJourney(stops: deliveryStops, gpsStream: SmartLocation.stream);
SmartLocation.journey.arrivals.listen((event) => print('Arrived at stop ${event.stopIndex}'));
// 3. OS Health Monitor (Silent Death Prevention)
SmartLocation.health.startMonitoring();
SmartLocation.health.degradationAlerts.listen((event) => print('OS constrained location: ${event.reason}'));
// 4. Severe Crash Detector
SmartLocation.crash.startMonitoring(SmartLocation.stream);
SmartLocation.crash.crashAlerts.listen((alert) => print('SOS! Crash detected! ${alert.decelerationGForce} Gs'));
Error Handling #
Always wrap location requests in a try-catch to handle disabled services and permission states:
try {
await SmartLocation.ensureReady();
final loc = await SmartLocation.current();
} on LocationDisabledException {
// GPS is OFF → prompt user to enable
} on PermissionDeniedException {
// Permission denied (can ask again)
} on PermissionPermanentlyDeniedException {
// Denied forever → open app settings
} catch (e) {
// Other unexpected errors
}
Best Practices #
- Always call
ensureReady()before accessing location data. - Use
distanceFilterinstreamWithSettingsor utilizeEcoOptimizerrecommendations to save battery. - Use
lastKnown()to populate the UI instantly on startup. - Always handle all three permission exception types explicitly.
- Cancel stream subscriptions when they are no longer needed to prevent memory leaks.