100 lines
4.3 KiB
Markdown
100 lines
4.3 KiB
Markdown
# Maps & routing
|
|
|
|
Fully open source, no API key, no account, no card.
|
|
|
|
| Concern | Technology | Cost |
|
|
| --- | --- | --- |
|
|
| Rendering | [MapLibre GL](https://maplibre.org) (BSD) | free |
|
|
| Tiles | [OpenFreeMap](https://openfreemap.org) — OSM data, MIT | free, no key, no limits |
|
|
| Routing | [OSRM](https://project-osrm.org) (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:
|
|
|
|
```sh
|
|
flutter run
|
|
```
|
|
|
|
Both endpoints are overridable at build time, so production can point at
|
|
self-hosted infrastructure without a code change:
|
|
|
|
```sh
|
|
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. See [`deploy/osrm/README.md`](../deploy/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=polyline` returns an encoded polyline at
|
|
**precision 5**. OSRM's `polyline6` option is precision 6; pass
|
|
`precision: 6` to `decodePolyline` if you ever switch.
|
|
- `_parse()` is deliberately tolerant — plain-number *or* `{"value": n}`
|
|
distances, several geometry key names, GeoJSON `LineString` — 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.** `RoutingService` caches 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.onTap` drives the customer sheet on the multi-stop screen),
|
|
but the old tap-to-show-title bubbles are gone.
|
|
- **Traffic and 3D buildings.** `trafficEnabled` / `buildingsEnabled` on 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.
|