Skip to content
Merged
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
5 changes: 4 additions & 1 deletion docs/navigation/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ export function NavigationScreen() {

`Navigation.previewRoute(route)` shows a route on navigation maps before guidance starts, and `Navigation.setCameraState('overview')` fits the rest of the route.

To guide on the device's location, pass `simulate: false` and request location permission first, see [Location permission](install.md#location-permission).

## Guidance events

Subscribe to the events you need while guidance runs. Each listener returns a subscription; `remove()` it on unmount.
Expand Down Expand Up @@ -107,7 +109,7 @@ useEffect(() => {
| `addLocationListener` | Location snapped to the road or route, with `speed`, `course`, `roadName` and `speedLimit`. |
| `addArriveListener` | `{ waypointIndex, isFinalDestination }` when a waypoint is reached; the origin is index 0. |
| `addOffRouteListener` | `true` when the user leaves the route, `false` once guidance follows a route again. |
| `addRouteChangeListener` | `{ route, reason }` when guidance switches to a new `Route` after a reroute. |
| `addRouteChangeListener` | `{ route, reason }` when guidance switches to a new `Route`, after a reroute or to an alternative. |
| `addVoiceInstructionListener` | `{ text, ssml, distanceAlongStep }`, for apps doing their own text to speech. |
| `addCameraStateListener` | Camera state changes, see [Camera](#camera). |

Expand All @@ -121,6 +123,7 @@ The SDK speaks voice instructions during any guidance; `Navigation.setVoiceMuted
- `release()` frees the native route. Release the routes you don't keep, such as unused alternatives. The garbage collector releases the rest eventually, but it doesn't see the native memory, so that can take long.
- After `release()`, reading anything but `isReleased` throws an `Error` with `code: 'route_released'`, and `startActiveGuidance` and `previewRoute` reject or throw it.
- Guidance and the preview keep their own reference to the native route until `stopNavigation`, so releasing a route they use is safe.
- `Navigation.getRouteStats()` returns `{ live, released, collected }` counts, for leak checks.
- Routes don't survive a JS reload.

## Navigation maps
Expand Down
97 changes: 63 additions & 34 deletions docs/navigation/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,35 @@ description: "Install @rnmapbox/navigation for turn-by-turn navigation in React
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

Set up `@rnmapbox/maps` first, following its [install guide](../install.md). `@rnmapbox/navigation` needs `@rnmapbox/maps` 10.3.11 or newer.

`@rnmapbox/navigation` is published under the `next` tag while it's in alpha.
Set up `@rnmapbox/maps` first, following its [install guide](../install.md). `@rnmapbox/navigation` 0.1.0 needs `@rnmapbox/maps` `>=10.3.16 <10.4.0` and React Native 0.79+ with the New Architecture.

## Install

Pin `@rnmapbox/maps` to the 10.3 line, so a later 10.4 outside the supported range isn't picked up:

<Tabs groupId="install-module" queryString defaultValue="npm" values={[
{label:'NPM', value:'npm'},
{label:'Yarn', value:'yarn'}
{label:'Yarn', value:'yarn'},
{label:'Expo', value:'expo'}
]}>
<TabItem value="npm">

```bash
npm install @rnmapbox/navigation@next @rnmapbox/maps
npm install @rnmapbox/navigation @rnmapbox/maps@~10.3.16
```

</TabItem>
<TabItem value="yarn">

```bash
yarn add @rnmapbox/navigation@next @rnmapbox/maps
yarn add @rnmapbox/navigation @rnmapbox/maps@~10.3.16
```

</TabItem>
<TabItem value="expo">

```bash
npx expo install @rnmapbox/navigation @rnmapbox/maps@~10.3.16
```

</TabItem>
Expand Down Expand Up @@ -66,25 +74,23 @@ end

`pod install` adds `MapboxCommon`, `MapboxCoreMaps`, `MapboxNavigationNative` and `Turf` to the frameworks CocoaPods embeds.

With React Native 0.87+ and Xcode 26, also add the Navigation SDK's binary frameworks to `rnmapbox-maps`' framework search paths, see [Troubleshooting](troubleshooting.md#xcode-26-unable-to-resolve-module-dependency-turf).

### Info.plist

Add `NSLocationWhenInUseUsageDescription`. For `<NavigationView>`, also add `audio` to `UIBackgroundModes`: the SDK's voice controller asserts on it in debug builds.
Add `NSLocationWhenInUseUsageDescription`, and `audio` to `UIBackgroundModes` so voice instructions keep playing in the background. The Navigation SDK's voice controller asserts on the `audio` mode in debug builds when guidance starts. Declare it only if your app speaks guidance; App Review rejects unused background modes.

### Versions

Set these before `use_native_modules!` if you need to:

```ruby
# Navigation SDK version, defaults to 3.23.1. Nav 3.N pins Maps 11.N.
$RNMapboxNavigationVersion = '3.23.1'
# Navigation SDK version, defaults to 3.33.0. Nav 3.N pins Maps 11.N.
$RNMapboxNavigationVersion = '3.33.0'
# Don't add the Swift package; add mapbox-navigation-ios (products MapboxNavigationCore and
# MapboxNavigationUIKit) yourself.
$RNMapboxNavigationSwiftPackageManager = 'manual'
```

`@rnmapbox/maps`' package requirement comes from `$RNMapboxMapsVersion` (default `~> 11.23.1`) and must be compatible with the Maps version the Navigation SDK pins, otherwise Xcode reports a package resolution error. With a newer Navigation SDK, set `$RNMapboxMapsVersion = '= 11.N.x'` to match.
`@rnmapbox/maps`' package requirement comes from `$RNMapboxMapsVersion` (default `~> 11.33.0`) and must be compatible with the Maps version the Navigation SDK pins, otherwise Xcode reports a package resolution error. With a newer Navigation SDK, set `$RNMapboxMapsVersion = '= 11.N.x'` to match.

</TabItem>
<TabItem value="android">
Expand All @@ -97,10 +103,10 @@ Add the Mapbox Maven repository, the same one `@rnmapbox/maps` uses, and set the
// android/build.gradle
buildscript {
ext {
// Nav 3.23.1 pins Maps 11.23.1. Both packages must resolve the same Maps.
RNMapboxMapsVersion = '11.23.1'
// Optional, defaults to 3.23.1.
RNMapboxNavigationVersion = '3.23.1'
// Nav 3.33.0 pins Maps 11.33.0. Both packages must resolve the same Maps.
RNMapboxMapsVersion = '11.33.0'
// Optional, defaults to 3.33.0.
RNMapboxNavigationVersion = '3.33.0'
}
}

Expand All @@ -111,7 +117,7 @@ allprojects {
}
```

`@rnmapbox/navigation` adds a strict constraint on the Maps version its Navigation SDK is built against, so a different `RNMapboxMapsVersion` fails dependency resolution instead of silently mixing versions.
`@rnmapbox/navigation` adds a strict constraint on the Maps version its Navigation SDK is built against (Nav 3.N → Maps 11.N, or `RNMapboxNavigationMapsVersion`), so a different `RNMapboxMapsVersion` fails dependency resolution instead of silently mixing versions.

With `targetSdkVersion` 35 or higher both libraries use the `-ndk27` artifacts (16 KB pages). Keep `targetSdkVersion` in the root project `ext`, where both libraries read it.

Expand All @@ -124,46 +130,44 @@ Use a [development build](https://docs.expo.dev/develop/development-builds/intro
{
"expo": {
"plugins": [
["@rnmapbox/maps", { "RNMapboxMapsVersion": "11.23.1" }],
["@rnmapbox/maps", { "RNMapboxMapsVersion": "11.33.0" }],
"@rnmapbox/navigation"
]
}
}
```

The `@rnmapbox/navigation` plugin only changes iOS:
Keep `RNMapboxMapsVersion` at the Maps SDK version the Navigation SDK pins (11.33.0 for Navigation SDK 3.33.0).

On iOS the `@rnmapbox/navigation` plugin:

- sets `$RNMapboxMapsSwiftPackageManager = { link: false }` in the Podfile, see the iOS tab;
- adds the Navigation SDK's binary frameworks to `rnmapbox-maps`' framework search paths, which Xcode 26 needs with React Native 0.87+;
- sets `NSLocationWhenInUseUsageDescription`, unless `locationWhenInUsePermission` is `false`.
- sets `NSLocationWhenInUseUsageDescription`, unless `locationWhenInUsePermission` is `false`;
- adds `audio` to `UIBackgroundModes`, so voice instructions keep playing in the background, unless `backgroundAudio` is `false`. Without it the Navigation SDK asserts in debug builds when guidance starts. Turn it off if your app doesn't speak guidance; App Review rejects unused background modes;
- with `carPlay: true`, adds the CarPlay scene and the `com.apple.developer.carplay-maps` entitlement, and with `carPlayRoot: true` also hands the `AppDelegate.swift` React Native factory to CarPlay.

On Android the `@rnmapbox/maps` plugin already adds the Mapbox Maven repository, and the Navigation SDK's manifest adds the location, foreground service and notification permissions.
On Android the `@rnmapbox/maps` plugin already adds the Mapbox Maven repository, and the Navigation SDK's manifest adds the location, foreground service and notification permissions. With `androidAuto: true` the `@rnmapbox/navigation` plugin adds the Android Auto service, its metadata and the `androidx.car.app` navigation and surface permissions. With `RNMapboxNavigationVersion` it sets the Navigation SDK version in `gradle.properties`.

### Options

```json
["@rnmapbox/navigation", {
"RNMapboxNavigationVersion": "3.23.1",
"RNMapboxNavigationVersion": "3.33.0",
"locationWhenInUsePermission": "Shows your location during navigation."
}]
```

| Option | Description |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `RNMapboxNavigationVersion` | Navigation SDK version on both platforms. Set the maps plugin's `RNMapboxMapsVersion` to the matching 11.N. |
| `locationWhenInUsePermission` | iOS `NSLocationWhenInUseUsageDescription`, or `false` to leave it unset. |

For `<NavigationView>` on iOS, also add the `audio` background mode, which the plugin doesn't set:
| `locationWhenInUsePermission` | iOS `NSLocationWhenInUseUsageDescription`, or `false` to leave it unset. Defaults to a generic navigation string, unless the app already sets one. |
| `backgroundAudio` | `false` leaves iOS `UIBackgroundModes` unchanged. Defaults to `true`, which adds `audio`. |
| `carPlay` | iOS CarPlay scene and entitlement. CarPlay is a prototype. |
| `carPlayRoot` | With `carPlay`, lets CarPlay start React Native for `Navigation.registerCarPlayRoot` when it launches the app without its phone UI. Needs a Swift `AppDelegate`. |
| `androidAuto` | Android Auto service and permissions. Experimental, not tested on a head unit yet. |

```json
{
"expo": {
"ios": {
"infoPlist": { "UIBackgroundModes": ["audio"] }
}
}
}
```
Turning `carPlay`, `carPlayRoot` or `androidAuto` off removes what they added on the next prebuild, except the entitlement and the permissions; `prebuild --clean` removes those too. See [CarPlay](https://github.com/rnmapbox/navigation#carplay) and [Android Auto](https://github.com/rnmapbox/navigation#android-auto) in the README for what they show.

### Build

Expand All @@ -190,4 +194,29 @@ Mapbox.setAccessToken('pk....');
Navigation.setAccessToken('pk....');
```

## Location permission

The app must have runtime location permission before guidance on the device's location (`simulate` off). Simulated guidance doesn't need it.

- Android: the Navigation SDK's manifest declares the location permissions, but the app has to request them at runtime, e.g. with `Mapbox.requestAndroidLocationPermissions()` from `@rnmapbox/maps`, which resolves to whether they were granted. It throws on iOS.
- iOS: set `NSLocationWhenInUseUsageDescription` (the Expo plugin sets it). The Navigation SDK asks for when-in-use authorization itself; ask from your own UI first, e.g. with `expo-location`, if you want to explain why.

```tsx
import { Platform } from 'react-native';
import Mapbox from '@rnmapbox/maps';
import Navigation, { type Route } from '@rnmapbox/navigation';

async function startGuidance(route: Route) {
if (
Platform.OS === 'android' &&
!(await Mapbox.requestAndroidLocationPermissions())
) {
return; // Denied: tell the user why navigation needs their location.
}
await Navigation.startActiveGuidance(route, { simulate: false });
}
```

See [Configure permissions for location access](../install.md#configure-permissions-for-location-access) in the `@rnmapbox/maps` install guide for the manifest and `Info.plist` entries.

Next: [Getting started](getting-started.md).
4 changes: 2 additions & 2 deletions docs/navigation/navigation-view.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ description: "The Mapbox Navigation SDK's full-screen turn-by-turn UI for React

`<NavigationView>` is a full-screen turn-by-turn navigation UI: `NavigationViewController` from `MapboxNavigationUIKit` on iOS, and an equivalent built from the Navigation SDK UI components on Android (maneuver banner with lanes and shields, speed limit, trip progress, mute, overview, recenter and end buttons).

On iOS, add `audio` to `UIBackgroundModes` in `Info.plist`, see [Install](install.md).
On iOS it needs `audio` in `UIBackgroundModes`, which the Expo config plugin adds; in a bare app add it to `Info.plist`, see [Install](install.md).

```tsx
import { NavigationView } from '@rnmapbox/navigation';
Expand Down Expand Up @@ -54,4 +54,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, feedback or alternative-route 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 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).
25 changes: 15 additions & 10 deletions docs/navigation/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,16 @@ It requests routes, runs an active-guidance session and reports route progress.
caption="<NavigationView> with a simulated route, on Android."
/>

:::caution Alpha
`@rnmapbox/navigation` is in early alpha. The current release is `0.1.0-alpha.1`, published to npm under the `next` tag, and APIs may change between releases.
:::note Pre-1.0
The current release is `0.1.0`, on npm's `latest` tag. APIs may change between minor releases until 1.0.
:::

## Requirements

- React Native 0.79+ with the New Architecture.
- `@rnmapbox/maps` 10.3.11 or newer (peer dependency). Navigation maps plug into its map view factory hooks, which have their current form since 10.3.11.
- iOS: React Native's minimum deployment target. The Navigation SDK for iOS 3.23.1 is added as a Swift package.
- Android: `minSdkVersion` 24, `compileSdkVersion` 36.
- `@rnmapbox/maps` `>=10.3.16 <10.4.0` (peer dependency). Navigation maps plug into its map view factory hooks, and `<CarMap>` into its support for maps that live elsewhere, which 10.3.16 completed.
- iOS: React Native's minimum deployment target (the Navigation SDK itself needs iOS 14). The Navigation SDK for iOS 3.33.0 is added as a Swift package.
- Android: `minSdkVersion` 24, `compileSdkVersion` 36. Navigation SDK for Android 3.33.0.
- A Mapbox account and a public access token (`pk.…`). No secret downloads token is needed.

Navigation is billed per trip or MAU to the access token you pass, on top of Maps usage. See [Navigation SDK pricing](https://www.mapbox.com/pricing#navigation).
Expand All @@ -57,9 +57,11 @@ Navigation is billed per trip or MAU to the access token you pass, on top of Map

The Navigation SDK pins the Maps SDK it's built against, and `@rnmapbox/maps` must use that same Maps SDK.

| @rnmapbox/navigation | Navigation SDK | Maps SDK (pinned by Nav) |
| -------------------- | -------------- | ------------------------ |
| 0.1.x | 3.23.1 | 11.23.1 |
| @rnmapbox/navigation | Navigation SDK | Maps SDK (pinned by Nav) | @rnmapbox/maps |
| ----------------------- | -------------- | ------------------------ | ------------------- |
| 0.1.0 | 3.33.0 | 11.33.0 | `>=10.3.16 <10.4.0` |
| 0.1.0-alpha.3 | 3.33.0 | 11.33.0 | `>=10.3.12 <10.4.0` |
| 0.1.0-alpha.0 – alpha.2 | 3.23.1 | 11.23.1 | `10.3.11` |

## What's included

Expand All @@ -69,6 +71,9 @@ The Navigation SDK pins the Maps SDK it's built against, and `@rnmapbox/maps` mu
- Events for route progress, camera state, location, arrival, off-route, reroutes and voice instructions.
- [`<NavigationView>`](navigation-view.md), the SDK's full-screen turn-by-turn UI.
- [`<RNNavigationView>`](rn-navigation-view.md), a turn-by-turn UI written in React Native on top of the headless API.
- [`<CarMap>`](api/Components/CarMap.md), which adds `@rnmapbox/maps` sources and layers to the car screen's map.
- CarPlay, a prototype: the Navigation SDK's CarPlay UI for the same navigation session as the phone. See [CarPlay](https://github.com/rnmapbox/navigation#carplay) in the README.
- Android Auto, experimental and not tested on a head unit yet: a navigation map for the same session. See [Android Auto](https://github.com/rnmapbox/navigation#android-auto) in the README.
- An Expo config plugin, see [Install](install.md).

## Choose an approach
Expand All @@ -87,8 +92,8 @@ Start with `<RNNavigationView>` if you want a ready UI that matches the rest of
## 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.
- Navigation maps show no alternative routes during guidance.
- Android `<NavigationView>` has no end-of-route, feedback or alternative-route 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 day/night styles, 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.
- One navigation session for all navigation maps. Per-map routes or cameras aren't supported.
Expand Down
Loading
Loading