session.navigation runs a turn-by-turn trip. Call start() with a destination,
then read live maneuvers from onUpdate() as the user moves. The phone owns the
trip lifecycle; your miniapp starts it, listens, and stops it.
src/background/index.ts
LOCATION permission in your
manifest. The gated methods
(requestPermission, start, computeRoute) check the declaration before doing
anything; without it they resolve {ok: false, error} and never reach the phone.
Navigation works on both iOS and Android. Every method resolves with an
{ok, error?} shape and nothing throws, so branch on result.ok rather than
wrapping in try/catch.Permission
session.navigation.hasPermission is true when LOCATION is declared in your
manifest. It reports the declaration, not the OS grant: if the user denied the
system location prompt, a trip still won’t get fixes.
requestPermission() confirms the navigation SDK’s terms up front, before the
user hits start. On platforms with a terms gate it shows the dialog; where there
isn’t one it resolves immediately. It’s idempotent, and resolves a
NavPermissionResult:
Starting a trip
start(options) accepts a single destination (lat / lng) or an ordered list
of stops. A resolved {ok: true} means the phone accepted the request, not that
a route exists yet. Watch onUpdate() and onRoute() for the route and live
maneuvers.
Travel modes
mode is one of:
Live updates
onUpdate(handler) delivers a NavUpdate every time the trip changes. Discriminate
on kind. It returns an unsubscribe function.
On a
"maneuver", prefer instruction (the host’s verbatim text, render as-is)
and nextStepRoad (the street after the turn) over the legacy toRoad field.
Distance and time fields use -1 for unknown; the speed and heading fields use
null.
The route polyline
onRoute(handler) fires once per route build, on the initial start and again on
each reroute, with the full path. It returns an unsubscribe function.
NavRoute carries points (the polyline as LatLng[]), optional
totalDistanceMeters and totalDurationSeconds, and optional steps (ordered
NavStep segments, each ending in a maneuver).
Reading current state
getState() resolves a NavState snapshot of the running trip, or null when no
trip is active. It’s shaped like the streaming events, so a miniapp opened
mid-trip can hydrate without waiting for the next update.
Stopping
stop() ends the active trip and detaches pivot tracking. It’s fire-and-forget
and a no-op when nothing is running.
Computing a route without starting
computeRoute(options) returns route geometry without starting a trip. Use it to
preview a route or show distance and time before the user commits.
It resolves
{ok, error?, routes?}. Each ComputedRoute has points,
totalDistanceMeters, totalDurationSeconds, an optional summary, and optional
steps. The primary route is first; alternates follow.
Pivots
A pivot is a real turn along the route (a left or right), derived once per route build and re-derived on reroute. Pivots let you cue the user as a turn approaches rather than reacting to raw maneuver updates.onPivot(handler) subscribes to pivot events and returns an unsubscribe function.
Each pivot fires approaching → entered → exited, once per kind, then the
cursor advances to the next pivot.
A
Pivot carries its index, lat / lng, direction ("left" or "right"),
the fromRoad and toRoad names (each null when the engine has none), the
maneuver, the distanceAlongRouteMeters from trip start, and the radiusMeters
that counts as “turning now”.
Tune detection per trip with pivots on start(): radiusMeters sets the
“turning now” radius and approachThresholdMeters sets the “approaching” radius.
Both fall back to mode-aware defaults when omitted.
Simulation helpers
session.navigation.dev holds simulator-only helpers for testing trips, including
deviate(offsetMeters), which nudges the simulated position off-route to trigger a
reroute. These are dev tooling, not part of a normal trip flow.
