Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions docs/navigation/free-drive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
id: free-drive
sidebar_position: 6
title: "Free drive: road name and speed limit without a route"
sidebar_label: Free drive
description: "Track the device on the road network without a route with @rnmapbox/navigation: road name, speed limit, the navigation puck and the session state."
---

Outside guidance the navigation session is idle: no location events and no puck on navigation maps. `Navigation.startFreeDrive()` matches the device's location to the road network without a route, so `addLocationListener` reports the road name and speed limit, and navigation maps show the puck. `Navigation.stopNavigation()` ends it.

```tsx
import { useEffect, useState } from 'react';
import Navigation, { type LocationEvent } from '@rnmapbox/navigation';

export function useFreeDrive() {
const [location, setLocation] = useState<LocationEvent>();

useEffect(() => {
const subscription = Navigation.addLocationListener(setLocation);
Navigation.startFreeDrive().catch((error) => {
// error.code === 'location_permission': ask for the permission first
console.warn(error);
});
return () => {
subscription.remove();
Navigation.stopNavigation();
};
}, []);

return location; // location?.roadName, location?.speedLimit?.speed, location?.speedLimit?.unit
}
```

- Mapbox bills free drive trips like guidance trips, see [Navigation SDK pricing](https://www.mapbox.com/pricing#navigation). Nothing in this package starts free drive on its own, CarPlay included. It runs from `startFreeDrive` until `stopNavigation` or a JS reload.
- Without location permission, `startFreeDrive` rejects with `code: 'location_permission'`, see [Location permission](install.md#location-permission).
- During guidance, `startFreeDrive()` ends the guidance and keeps the session in free drive.
- `<NavigationView>` and `<RNNavigationView>` started from free drive return to it when they unmount or the user ends the trip.

`speedLimit` is missing where the road has no known limit. Its `sign` is `'mutcd'` (US-style rectangle) or `'vienna'` (red circle), see [`LocationEvent`](api/Events/LocationEvent.md).

## Simulated location

`startFreeDrive({ simulatedLocation: [longitude, latitude] })` parks a simulated device at that position instead of using the device's location, and needs no location permission. After simulated guidance, `startFreeDrive()` keeps the simulated device where guidance stopped.

## Android background tracking

On Android, free drive runs without the Navigation SDK's foreground service, so Android throttles its location updates while the app is in the background. `startFreeDrive({ foregroundService: true })` keeps tracking in the background with the SDK's notification, which also keeps the billed trip going while the app isn't visible, until `stopNavigation`. Live guidance always uses the foreground service. iOS and simulated free drive ignore the option.

## Session state

`Navigation.getSessionState()` returns `'idle'`, `'freeDrive'` or `'activeGuidance'`, and `addSessionStateListener` reports changes, whether they come from JS, `<NavigationView>` or the car screen.

```tsx
const [sessionState, setSessionState] = useState(Navigation.getSessionState);

useEffect(() => {
const subscription = Navigation.addSessionStateListener(setSessionState);
return () => subscription.remove();
}, []);
```

On iOS they follow the SDK's session; on Android they follow this package's calls.
71 changes: 71 additions & 0 deletions docs/navigation/guidance-controls.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
id: guidance-controls
sidebar_position: 7
title: "Guidance controls: stops, simulation speed, voice and screen"
sidebar_label: Guidance controls
description: "Control a running @rnmapbox/navigation guidance session: advance between stops, simulation speed, voice volume and mute, and keeping the screen on."
---

These settings apply to the app's single navigation session, so they also affect `<NavigationView>` and `<RNNavigationView>`.

## Multi-stop routes

Each non-silent waypoint after the origin ends a leg, see [Waypoints](route-options.md#waypoints). When guidance arrives at one, `addArriveListener` reports `{ waypointIndex, isFinalDestination }` and guidance moves on to the next leg by itself.

To wait at each stop, e.g. until a delivery is confirmed, turn that off and advance yourself:

```tsx
import { Alert } from 'react-native';
import Navigation from '@rnmapbox/navigation';

Navigation.setAutoAdvanceLegs(false);

const subscription = Navigation.addArriveListener(({ isFinalDestination }) => {
if (!isFinalDestination) {
Alert.alert('Delivered?', undefined, [
{ text: 'Next stop', onPress: () => Navigation.advanceToNextLeg() },
]);
}
});
```

- With auto-advance off, guidance stays at the waypoint until `advanceToNextLeg()`, simulated guidance included. Turning it back on while guidance waits doesn't move on; call `advanceToNextLeg()`.
- `advanceToNextLeg()` also skips a stop. Away from the waypoint, guidance reroutes from where it is; simulated guidance jumps to the start of the next leg and reroutes again.
- It does nothing on the last leg or without active guidance.

## Simulation speed

`Navigation.setSimulationSpeed(multiplier)` drives simulated guidance faster or slower than the route's expected speeds, e.g. `2` for twice as fast. The default is `1`. It applies to the running simulation and later ones, and throws unless `multiplier` is positive.

```tsx
Navigation.setSimulationSpeed(2);
await Navigation.startActiveGuidance(route, { simulate: true });
```

- Simulated locations keep reporting the route's speed, not multiplied.
- Higher speeds can make guidance go off route at sharp turns and reroute. This was seen at U-turns from 4× on Android and at 8× on iOS.
- On Android the simulation doesn't follow reroutes, so after one it can stop short of the destination.

## Voice

The SDK speaks voice instructions during any guidance.

| Function | Description |
| ------------------------ | ----------------------------------------------------------------------------------- |
| `setVoiceMuted(muted)` | Mutes or unmutes them. `<NavigationView>`'s mute button toggles the same setting. |
| `isVoiceMuted()` | Whether they're muted, by `setVoiceMuted` or the mute button. |
| `setVoiceVolume(volume)` | Volume from 0 to 1, relative to the device's media volume, clamped to that range. Independent of mute. Throws for `NaN`. |

On iOS the volume doesn't apply to instructions spoken by the system voice, which the SDK falls back to when the Mapbox voice is unavailable, e.g. offline.

For your own text to speech, mute the SDK and subscribe to `addVoiceInstructionListener`, which is called whether or not the SDK speaks.

## Keep screen on

Active guidance, `<NavigationView>`'s included, keeps the screen on. When guidance stops, the app's own idle timer (iOS) or keep screen on (Android) setting is restored. If the app manages that itself, turn it off:

```tsx
Navigation.setKeepScreenOn(false);
```

See [`Navigation`](api/Core/Navigation.md) in the API reference.
51 changes: 51 additions & 0 deletions docs/navigation/map-matching.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
id: map-matching
sidebar_position: 5
title: "Guide along your own path with Map Matching"
sidebar_label: Map Matching
description: "Turn a list of coordinates, such as a tour or a delivery run, into a navigable route with the Mapbox Map Matching API and @rnmapbox/navigation."
---

`Navigation.requestMatchedRoutes` snaps a path the app defines, such as a tour or a delivery run, to roads with the [Mapbox Map Matching API](https://docs.mapbox.com/api/navigation/map-matching/), and resolves with a route along it. Use it when the route has to follow your path, rather than the fastest route between the waypoints that `requestRoutes` returns.

```tsx
import Navigation, { type Position } from '@rnmapbox/navigation';

const TOUR: Position[] = [
[-122.39726, 37.79205],
[-122.39612, 37.79310],
[-122.39480, 37.79420],
[-122.39351, 37.79554],
];

const { main } = await Navigation.requestMatchedRoutes({
coordinates: TOUR,
waypointIndices: [0, 2, TOUR.length - 1],
});
await Navigation.startActiveGuidance(main, { simulate: true });
```

The route works with `previewRoute` and `startActiveGuidance` like one from `requestRoutes`, and holds native memory the same way: `release()` it when you're done. `alternatives` is always empty.

## Options

| Option | Description |
| ----------------- | ----------------------------------------------------------------------------------------------- |
| `coordinates` | The path, 2 to 100 positions in order. Each is snapped to the nearest road within its radius, so a sparse trace works. |
| `profile` | `'driving-traffic'` (default), `'driving'`, `'walking'` or `'cycling'`. |
| `waypointIndices` | Indices of the `coordinates` that are waypoints: the route is split into legs there, and guidance announces the arrival. Ascending, including the first and last index. Defaults to the first and last coordinate. |
| `radiuses` | Meters each coordinate may be away from the road, one per coordinate, 0 to 50. The API defaults to 5. |
| `language` | Language of the instructions, e.g. `en` or `de-DE`. |
| `units` | `'metric'` or `'imperial'`, for the distances in voice instructions. |

It rejects without sending a request if the options break these limits, and with `code: 'no_single_match'` if the API can only match the coordinates as several disconnected pieces, e.g. across a gap with no road. Add coordinates in the gap, or raise `radiuses` there.

## Off route

Neither SDK reroutes a matched route, whatever `setRerouteEnabled` says. When the user leaves it, `addOffRouteListener` reports `true` and guidance waits for them to return to the route.

## Platform notes

On Android this uses the SDK's `requestMapMatching`, which the Navigation SDK marks as experimental, so its behavior may change in minor releases.

See [`MatchedRouteRequestOptions`](api/Routes/MatchedRouteRequestOptions.md) in the API reference.
6 changes: 4 additions & 2 deletions docs/navigation/navigation-view.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
id: navigation-view
sidebar_position: 4
sidebar_position: 9
title: "NavigationView: drop-in turn-by-turn navigation UI"
sidebar_label: NavigationView
description: "The Mapbox Navigation SDK's full-screen turn-by-turn UI for React Native on iOS and Android, with maneuver banner, lanes, speed limit and trip progress."
Expand Down Expand Up @@ -38,6 +38,8 @@ See [`NavigationViewProps`](api/Components/NavigationViewProps.md) in the API re
| `waypoints` | `Waypoint[]` | Used without `route`: the view requests a route through them, origin first, and releases it on unmount. |
| `simulate` | `boolean` | Drives the route with simulated locations. Read when guidance starts. Defaults to `false`. |
| `mute` | `boolean` | Mutes voice instructions. The view's own mute button also toggles them. Defaults to `false`. |
| `styleURL` | `string` | Map style by day. Defaults to Mapbox Standard. See [Styling](styling.md#map-styles). |
| `nightStyleURL` | `string` | Map style while the system is in dark mode. Defaults to `styleURL`, or without it to Standard's night preset. |
| `style` | `StyleProp<ViewStyle>` | |
| `testID` | `string` | |
| `onRouteProgress` | `(event: RouteProgressEvent) => void` | Same event as `addRouteProgressListener`. |
Expand All @@ -54,4 +56,4 @@ See [`NavigationViewProps`](api/Components/NavigationViewProps.md) in the API re
- `addRouteProgressListener` and `addCameraStateListener` also report its guidance.
- Show one `NavigationView` at a time. On iOS it's embedded as a child of the nearest view controller.

Android `<NavigationView>` has no end-of-route or feedback UI, no day/night styles, no road name label, and doesn't show reroutes as such. For the same UI on both platforms, see [`<RNNavigationView>`](rn-navigation-view.md).
Android `<NavigationView>` has no end-of-route or feedback UI, no night colors for its UI (only the map switches), no road name label, and doesn't show reroutes as such. For the same UI on both platforms, see [`<RNNavigationView>`](rn-navigation-view.md).
4 changes: 2 additions & 2 deletions docs/navigation/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,15 @@ There are three ways to build a navigation screen. They all share the app's sing
| --- | --- | --- | --- |
| What you get | A navigation map with the route line, puck and camera. All UI is yours. | A complete UI in React Native: maneuver banner, lanes, speed limit, trip progress, buttons. | The Navigation SDK's own UI: `NavigationViewController` on iOS, the SDK UI components on Android. |
| Customizability | Full. Any `@rnmapbox/maps` layers, sources and annotations, any React Native UI. | High. Change the map style, add map children, or copy its source as a starting point. | Low. Props for the route, simulation and mute; the look is the SDK's. |
| Platform parity | Same on both platforms, since the UI is yours. | Same on both platforms. | Differs: Android has no end-of-route or feedback UI, no day/night styles and no road name label. |
| Platform parity | Same on both platforms, since the UI is yours. | Same on both platforms. | Differs: Android has no end-of-route or feedback UI, no night colors for its UI and no road name label. |
| Effort | Most: you build banners, buttons and arrival handling from the [events](api/index.md). | Little: drop it in, pass `waypoints` or a `route`. | Least, for the full SDK experience. |

Start with `<RNNavigationView>` if you want a ready UI that matches the rest of your React Native app, `<NavigationView>` if you want the SDK's UI as is, and the headless API when navigation is one part of a custom map screen.

## Known limitations

- No explicit offline routing API. Requests use the SDK's default hybrid router, which only falls back to onboard routing with routing tiles already on the device.
- Android `<NavigationView>` has no end-of-route or feedback UI, no day/night styles, no road name label, and doesn't show reroutes as such.
- Android `<NavigationView>` has no end-of-route or feedback UI, no night colors for its UI (only the map switches), no road name label, and doesn't show reroutes as such.
- `<RNNavigationView>` draws road shields from the Directions API's shield images, not the Mapbox designed shields the native banners use.
- The Expo config plugin is only tested with Expo SDK 58.
- `@rnmapbox/maps` `LocationPuck` and `UserLocation` don't work on navigation maps: the navigation puck replaces the map's location provider.
Expand Down
6 changes: 4 additions & 2 deletions docs/navigation/rn-navigation-view.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
id: rn-navigation-view
sidebar_position: 5
sidebar_position: 10
title: "RNNavigationView: turn-by-turn navigation UI in React Native"
sidebar_label: RNNavigationView
description: "A customizable turn-by-turn navigation UI written in React Native on top of the @rnmapbox/navigation headless API, the same on iOS and Android."
Expand Down Expand Up @@ -44,8 +44,10 @@ It takes the same props as [`<NavigationView>`](navigation-view.md#props) (`rout
| Prop | Type | Description |
| -------------- | ------------------------------- | ------------------------------------------------------------------------ |
| `distanceUnit` | `'metric' \| 'imperial'` | Unit of the distances it shows, and of the voice instructions of a route it requests through `waypoints`. Defaults to `Navigation.getDefaultDistanceUnit()`, from the device's region and measurement settings. |
| `appearance` | `'auto' \| 'day' \| 'night'` | Colors of the UI and the Standard style's light preset. `'auto'` (default) switches at sunrise and sunset at the user's location. |
| `appearance` | `'auto' \| 'day' \| 'night'` | Colors of the UI and the Standard style's light preset. `'auto'` (default) is night while the system is in dark mode. |
| `styleURL` | `string` | Map style. Defaults to Mapbox Standard. With another style, `appearance` only changes the UI. |
| `nightStyleURL` | `string` | Map style while `appearance` is night. Defaults to `styleURL`. |
| `routeLineStyle` | `RouteLineStyle` | Route line colors, see [Styling](styling.md#route-line-colors). |
| `children` | `ReactNode` | Rendered inside its `MapView`, e.g. extra sources and layers. |

See [`RNNavigationViewProps`](api/Components/RNNavigationViewProps.md) in the API reference.
Expand Down
Loading
Loading