4.3 KiB
Maps & routing
Fully open source, no API key, no account, no card.
| Concern | Technology | Cost |
|---|---|---|
| Rendering | MapLibre GL (BSD) | free |
| Tiles | OpenFreeMap — OSM data, MIT | free, no key, no limits |
| Routing | OSRM (BSD) | free, self-hostable |
There is no dependency on Google Maps: no Maps SDK, no Directions API, no
com.google.android.geo.API_KEY in the manifest, and no credential of any kind
shipped in the app.
Why
Google's mobile Maps SDK is free and unlimited — the bill came from the
Directions API at $5 per 1,000 requests above a 10,000/month free tier. Two
things made it worse: the multi-stop screen issued one Directions call per
route segment, and the API key was hardcoded in five places (including
AndroidManifest.xml), unrestricted because the routing calls went out from the
device as web-service requests.
Commercial alternatives were considered and rejected because they all want an account and a payment method. The open-source stack has neither.
Configuration
Nothing is required to run the app — the defaults work out of the box:
flutter run
Both endpoints are overridable at build time, so production can point at self-hosted infrastructure without a code change:
flutter build apk \
--dart-define=OSRM_BASE_URL=https://osrm.your-domain.in \
--dart-define=MAP_STYLE_URL=https://tiles.your-domain.in/styles/liberty
Before production, stand up your own OSRM. The default (
routing.openstreetmap.de) is the FOSSGIS community server — free and keyless, but donation-funded with a fair-use policy that a delivery fleet would abuse. Seedeploy/osrm/README.md; the Coimbatore region needs only a 0.52 GB extract.Tiles do not need self-hosting — OpenFreeMap's public instance has no key and no request limits, and permits commercial use under MIT with attribution (which MapLibre renders automatically).
Layout
| File | Role |
|---|---|
lib/services/maps/map_config.dart |
Tile style + routing endpoints |
lib/services/maps/routing_service.dart |
OSRM client, polyline decoding, response cache |
lib/services/maps/map_marker_icons.dart |
Canvas-drawn marker bitmaps (MapLibre has no built-in pins) |
lib/services/maps/nearle_map.dart |
The NearleMap widget — declarative markers/polylines over MapLibre |
Provider choice is confined to the first two files. The four map screens talk
only to NearleMap and RoutingService, so swapping backends again would not
touch UI code.
OSRM notes
- Coordinates go in the URL path as
lon,lat— the reverse of most APIs. overview=full&geometries=polylinereturns an encoded polyline at precision 5. OSRM'spolyline6option is precision 6; passprecision: 6todecodePolylineif you ever switch._parse()is deliberately tolerant — plain-number or{"value": n}distances, several geometry key names, GeoJSONLineString— so a proxy or an OSRM-compatible alternative (Valhalla, GraphHopper) drops in without changes.
Cost controls
These mattered when routing was billed and still cut latency and load:
- One call per route, not per leg. The multi-stop screen passes intermediate stops as additional coordinates in a single OSRM request. It previously issued one request per consecutive pair, so an N-stop route cost N calls every time the screen opened.
- Response cache.
RoutingServicecaches by origin/destination rounded to ~11 m for 30 minutes, so repeated quotes for the same delivery reuse one call. - Rendering makes no routing calls at all.
Known gaps vs. the old Google implementation
- Info windows. MapLibre has no info-window concept. Marker taps still fire
(
NearleMapMarker.onTapdrives the customer sheet on the multi-stop screen), but the old tap-to-show-title bubbles are gone. - Traffic and 3D buildings.
trafficEnabled/buildingsEnabledon the navigation screen had no MapLibre equivalent and were dropped. OSRM has no live-traffic model either — ETAs are free-flow estimates. - Turn-by-turn navigation is unchanged. It still hands off to whatever
navigation app is installed via a
google.navigation:/ maps URL intent. That is an OS intent, not an API — no key, no SDK, no billing.