osm_maps_engine
A complete, plug-and-play mapping and routing engine for Flutter, powered entirely by OpenStreetMap (OSM) and Open Source Routing Machine (OSRM).
This package provides a drop-in widget for real-time driver tracking, smooth marker animations, dynamic polyline rendering, and estimated time of arrival (ETA) calculation without relying on proprietary mapping APIs.
Read the article on my journal: Building Navigation Applications with OpenStreetMap
Preview
| Navigation Flow | Simulation Screen Record |
|---|---|
![]() |
![]() |
Table of Contents
- Features
- Installation
- Quick Start
- OsmMapWidget Parameters
- OsmMapCubit - Full API Reference
- MarkerMotionService - Full API Reference
- LocationTrackingService - Full API Reference
- MapCameraService - Full API Reference
- RouteCalculationService - Full API Reference
- Cost Optimization
- Platform Configuration
- License
Features
| Feature | Description |
|---|---|
| Plug-and-Play Widget | Drop OsmMapWidget into any screen. No boilerplate. |
| Gradient Polyline | Route line rendered with smooth color gradient toward destination. |
| Smooth Marker Animation | Driver icon glides along the route - no jumping or stuttering. |
| Smart Road Snapping | Driver marker stays clamped to the road polyline despite GPS jitter. |
| Auto Rerouting | Detects off-route movement and recalculates in background. |
| Zero-Cost Routing | Uses OSRM (OpenStreetMap) by default; 100% free and open-source. |
| iOS & Android | Optimized for both platforms, including background location. |
Installation
For Development (Local Path)
dependencies:
osm_maps_engine:
path: ../osm_maps_engine
For Production (pub.dev)
dependencies:
osm_maps_engine: ^0.0.8
Quick Start
import 'package:flutter/material.dart';
import 'package:latlong2/latlong.dart';
import 'package:osm_maps_engine/osm_maps_engine.dart';
class SimpleTrackingMap extends StatelessWidget {
const SimpleTrackingMap({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: OsmMapWidget(
origin: const LatLng(-6.200000, 106.816666),
destination: const LatLng(-6.2100, 106.8200),
driverIconWidget: const Icon(Icons.local_shipping, color: Colors.blue, size: 40),
destinationIconWidget: const Icon(Icons.flag, color: Colors.red, size: 40),
onLocationUpdated: (position) {
// Send to your backend every GPS tick
print('Driver: ${position.latitude}, ${position.longitude}');
},
),
);
}
}
OsmMapWidget Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
origin |
LatLng |
Yes | — | Starting coordinate (driver's current location) |
destination |
LatLng |
Yes | — | Destination coordinate (customer address) |
onLocationUpdated |
Function(Position)? |
No | null |
Callback fired on every GPS update |
driverIconWidget |
Widget? |
No | Navigation Icon | Custom Widget for driver marker |
destinationIconWidget |
Widget? |
No | Location Pin | Custom Widget for destination marker |
enableSimulation |
bool |
No | false |
Simulate driving along the route (for testing) |
OsmMapCubit - Full API Reference
The central state controller. Manages markers, polylines, camera, and rerouting.
Class Constants
| Constant | Type | Value | Description |
|---|---|---|---|
offRouteDistance |
double |
15.0 |
Meters off-route before rerouting is triggered |
offRouteThreshold |
int |
1 |
Consecutive off-route ticks before recalculating |
minSpeedForReroute |
double |
0.5 |
Min speed (m/s) for off-route detection to activate |
Constructor Parameters
OsmMapCubit({
void Function(Position)? onLocationUpdated,
Widget? driverIconWidget,
Widget? destinationIconWidget,
})
| Parameter | Type | Description |
|---|---|---|
onLocationUpdated |
Function(Position)? |
Fired on every real GPS update |
driverIconWidget |
Widget? |
Custom driver marker widget |
destinationIconWidget |
Widget? |
Custom destination marker widget |
Public Methods
| Method | Returns | Description |
|---|---|---|
initialize({required LatLng origin, required LatLng destination}) |
Future<void> |
One-time setup: loads route, sets up markers, starts GPS tracking |
selectRoute(int index) |
void |
Switch between alternative routes (index from state.alternativeRoutes) |
recalculateRoute() |
Future<void> |
Force reroute from current GPS position to existing destination |
toggleSimulation(bool enable) |
void |
Start/stop simulation mode |
close() |
Future<void> |
Disposes all timers and streams. Always call on dispose |
Internal Methods (For Contributors)
| Method | Returns | Description |
|---|---|---|
_setupMarkers(LatLng currentLocation, LatLng destination) |
void |
Creates driver and destination Marker objects with widgets |
_calculateAndSetRoute(LatLng start, LatLng end) |
Future<void> |
Calls RouteCalculationService, builds polylines, loads steps |
_generateRoutePolylines(List<RouteData> routes, int selectedIndex) |
List<Polyline> |
Builds all route polylines |
_buildGradientPolylines(List<LatLng> points) |
List<Polyline> |
Segments route into color-graded sections (blue to purple gradient) |
_startLocationTracking() |
void |
Starts LocationTrackingService stream and binds _handleLocationUpdate |
_handleLocationUpdate(Position position, {bool forceUpdate}) |
void |
Entry point for GPS updates: saves raw GPS, triggers marker animation |
_updateDriverMarker(LatLng position, double bearing, int routeIndex) |
void |
Updates marker position & bearing; trims polyline to remaining route |
_startRerouteCheck() |
void |
Starts a 2-second periodic timer that calls _checkOffRoute |
_checkOffRoute() |
void |
Measures driver distance from route polyline; increments _offRouteCount and calls recalculateRoute when threshold reached |
State Fields (OsmMapState)
| Field | Type | Description |
|---|---|---|
markers |
List<Marker> |
All visible map markers |
polylines |
List<Polyline> |
Currently drawn polylines (remaining route) |
currentLocation |
LatLng? |
Latest known driver position |
destinationLocation |
LatLng? |
Target destination |
isLoading |
bool |
True while loading initial route |
error |
String? |
Error message if any operation fails |
routeDuration |
String |
Remaining ETA ("7 mins") |
routeDistance |
String |
Remaining distance ("2.3 km") |
isTracking |
bool |
True when GPS tracking stream is active |
isRerouting |
bool |
True while recalculating route |
isSimulating |
bool |
True when simulation mode is active |
isNavigating |
bool |
True when navigation is active |
navigationSteps |
List<Map<String, dynamic>> |
List of navigation steps |
currentInstruction |
String? |
Active step instruction |
nextStepDistance |
double? |
Distance to next step |
currentBearing |
double |
Current heading in degrees (0–360) |
currentSpeed |
double |
Current speed in km/h |
alternativeRoutes |
List<RouteData> |
All calculated route alternatives |
selectedRouteIndex |
int |
Index of active route |
MarkerMotionService - Full API Reference
Smoothly animates a map marker from one position to another using frame-by-frame interpolation.
Public Methods
| Method | Returns | Description |
|---|---|---|
setRoutePoints(List<LatLng> points) |
void |
Sets the full route polyline for snapping and simulation |
reset() |
void |
Resets all position, bearing, and index state |
injectPosition(LatLng position, double bearing) |
void |
Force-sets position without animation |
moveTo({required LatLng target, required Function(LatLng, double, int) onUpdate, double? initialBearing, double? heading}) |
void |
Animate marker to target. |
startSimulation(Function(LatLng, double, int) onUpdate, {double speedKmh, bool fromBeginning}) |
void |
Begins automatic route simulation at given speed. |
stopSimulation() |
void |
Stops simulation timer |
dispose() |
void |
Cancels all timers and cleans up resources |
LocationTrackingService - Full API Reference
Wraps Geolocator to provide filtered, platform-optimized GPS streams.
Public Methods
| Method | Returns | Description |
|---|---|---|
getCurrentPosition({LocationAccuracy accuracy}) |
Future<Position?> |
One-shot: gets current GPS fix. |
getLastKnownPosition() |
Future<Position?> |
Returns last cached GPS position |
startTracking({required Function(Position) onPositionUpdate, Duration? interval, bool useStream}) |
void |
Start continuous GPS tracking. |
pauseTracking() |
void |
Temporarily stops the position stream |
resumeTracking() |
void |
Resumes a paused stream |
stopTracking() |
void |
Fully stops tracking and clears all listeners |
updateLocationSettings({int? interval, double? distanceFilter}) |
Future<void> |
Hot-update GPS interval and distance filter |
dispose() |
void |
Stops tracking and releases all resources |
MapCameraService - Full API Reference
Controls the MapController for centering and bounding.
Public Methods
| Method | Returns | Description |
|---|---|---|
setController(MapController controller) |
void |
Binds the MapController after map is created |
setMode(CameraMode mode) |
void |
Switch camera mode |
activateManualMode({Duration? autoResetDuration}) |
void |
Lock camera to manual. Auto-resets to center after timeout. |
centerToLocation(LatLng location, {double zoom}) |
void |
Move camera to a fixed location |
fitBounds(List<LatLng> points, {double padding}) |
void |
Fit camera to show all points with padding |
dispose() |
void |
Cancels all timers and cleans up resources |
RouteCalculationService - Full API Reference
Calculates routes using OSRM (free).
Public Methods
| Method | Returns | Description |
|---|---|---|
calculateRoutes(LatLng origin, LatLng destination) |
Future<List<RouteData>> |
Calculates all available routes (with alternatives). |
Cost Optimization
By default, routing uses OSRM (100% free, OpenStreetMap).
| Service | Proprietary Maps API Cost | OSRM (This Package) Cost | Savings |
|---|---|---|---|
| Routing / Directions | ~$5.00 / 1000 requests | $0.00 | 100% |
| Map Tiles Rendering | ~$7.00 / 1000 loads | $0.00 | 100% |
| Geocoding | ~$5.00 / 1000 requests | Use OSM Nominatim | ~95%+ |
Platform Configuration
Since this package uses geolocator, you must configure your native platforms to allow location access.
iOS (ios/Runner/Info.plist)
Add the following keys to your Info.plist:
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to location for live tracking.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs access to location when in the background.</string>
Android (android/app/src/main/AndroidManifest.xml)
Add the following permissions:
<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" />
License
This project is licensed under the MIT License.

