Real-Time Background GPS Telemetry and Map Routing in Flutter
Solving battery drain, GPS coordinate jitter, and 60 FPS marker interpolation in on-demand ride-hailing and courier apps.
Author: Syed Waleed Nawaz
Senior Flutter Developer & Mobile Backend Engineer
1. The Triad of Telemetry Constraints: Battery, Accuracy, Frame Rate
Building real-time on-demand applications—such as the Potolo ride-hailing platform and the Wasey courier dispatch engine—presents three conflicting constraints:
1. Battery Consumption: Polling GPS at maximum frequency rapidly depletes the device battery and triggers aggressive iOS/Android operating system termination.
2. Location Jitter: Raw GPS coordinates fluctuate significantly when stationary or in urban canyons, causing map markers to vibrate or jump across city blocks.
3. Rendering Performance: Naively calling setState() every time a new coordinate arrives causes dropped frames, micro-stutters, and battery-draining GPU layout passes.
Key Takeaway: A production location pipeline must decouple background OS location ingestion, server streaming, and front-end map marker animation.
2. Battery-Efficient Background Location Ingestion
To keep driver apps alive during 8-hour shifts without overheating or being killed by OS battery managers, we configure dynamic distance filters instead of raw time-interval polling.
When the vehicle is moving at high speeds (> 40 km/h), we prioritize distance-based location triggers (e.g., every 15 meters). When the driver is stationary at a red light or awaiting dispatch, we throttle telemetry down to 60-second heartbeats.
// Dynamic telemetry configuration for Flutter background location
LocationSettings getDynamicLocationSettings({required bool isDriving}) {
if (defaultTargetPlatform == TargetPlatform.android) {
return AndroidSettings(
accuracy: LocationAccuracy.high,
distanceFilter: isDriving ? 10 : 25, // meters
intervalDuration: const Duration(seconds: 3),
foregroundNotificationConfig: const ForegroundNotificationConfig(
notificationText: "Active dispatch navigation in progress",
notificationTitle: "Potolo Driver Active",
enableWakeLock: true,
),
);
} else {
return AppleSettings(
accuracy: LocationAccuracy.high,
activityType: ActivityType.automotiveNavigation,
distanceFilter: isDriving ? 10 : 25,
pauseLocationUpdatesAutomatically: true,
showBackgroundLocationIndicator: true,
);
}
}3. 60 FPS Vehicle Marker Interpolation with Bearing Rotation
If you update a Google Maps marker instantly from Coordinate A to Coordinate B, the vehicle icon teleports. For passenger trust, the marker must slide smoothly along the actual street bearing.
We use an AnimationController paired with spherical linear interpolation (lerp) over latitude/longitude coordinates and spherical bearing calculation:
void animateVehicleMarker({
required LatLng previousLocation,
required LatLng newLocation,
required MarkerId markerId,
required TickerProvider vsync,
}) {
final double targetBearing = calculateBearing(previousLocation, newLocation);
final controller = AnimationController(
duration: const Duration(milliseconds: 1200),
vsync: vsync,
);
final latTween = Tween<double>(begin: previousLocation.latitude, end: newLocation.latitude);
final lngTween = Tween<double>(begin: previousLocation.longitude, end: newLocation.longitude);
controller.addListener(() {
final interpolatedLatLng = LatLng(
latTween.evaluate(controller),
lngTween.evaluate(controller),
);
// Update only the specific marker in the controller without full page rebuild
updateMarkerPosition(markerId, interpolatedLatLng, targetBearing);
});
controller.forward().then((_) => controller.dispose());
}Key Takeaway: Decouple server telemetry updates (every 2-3 seconds) from visual rendering (smooth 60 FPS animated transitions).
4. Resilient WebSocket Telemetry Pipes
Couriers and drivers routinely drive through tunnels and dead zones. If your WebSocket connection drops, queued coordinates should not be dumped indiscriminately upon reconnect.
In the Potolo and Wasey platforms, coordinates are tagged with UTC timestamps. If a network drop occurs, the client buffers updates locally and transmits only the latest snapshot plus a compressed delta upon reconnection, preventing server event storms.
Ready to build your next production application?
Share your product scope, platform requirements, and target timeline. I'll provide a concrete architecture and deployment blueprint.