diff --git a/docs/navigation/getting-started.md b/docs/navigation/getting-started.md index 4bf4af32..5c0cd410 100644 --- a/docs/navigation/getting-started.md +++ b/docs/navigation/getting-started.md @@ -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. @@ -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). | @@ -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 diff --git a/docs/navigation/install.md b/docs/navigation/install.md index 94161e7b..35bfc0a1 100644 --- a/docs/navigation/install.md +++ b/docs/navigation/install.md @@ -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: + ```bash -npm install @rnmapbox/navigation@next @rnmapbox/maps +npm install @rnmapbox/navigation @rnmapbox/maps@~10.3.16 ``` ```bash -yarn add @rnmapbox/navigation@next @rnmapbox/maps +yarn add @rnmapbox/navigation @rnmapbox/maps@~10.3.16 +``` + + + + +```bash +npx expo install @rnmapbox/navigation @rnmapbox/maps@~10.3.16 ``` @@ -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 ``, 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. @@ -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' } } @@ -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. @@ -124,26 +130,30 @@ 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." }] ``` @@ -151,19 +161,13 @@ On Android the `@rnmapbox/maps` plugin already adds the Mapbox Maven repository, | 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 `` 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 @@ -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). diff --git a/docs/navigation/navigation-view.md b/docs/navigation/navigation-view.md index 9ee9bf3d..05d4a104 100644 --- a/docs/navigation/navigation-view.md +++ b/docs/navigation/navigation-view.md @@ -8,7 +8,7 @@ description: "The Mapbox Navigation SDK's full-screen turn-by-turn UI for React `` 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'; @@ -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 `` 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 [``](rn-navigation-view.md). +Android `` 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 [``](rn-navigation-view.md). diff --git a/docs/navigation/overview.md b/docs/navigation/overview.md index e7bc84aa..192b82b9 100644 --- a/docs/navigation/overview.md +++ b/docs/navigation/overview.md @@ -39,16 +39,16 @@ It requests routes, runs an active-guidance session and reports route progress. caption=" 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 `` 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). @@ -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 @@ -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. - [``](navigation-view.md), the SDK's full-screen turn-by-turn UI. - [``](rn-navigation-view.md), a turn-by-turn UI written in React Native on top of the headless API. +- [``](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 @@ -87,8 +92,8 @@ Start with `` 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 `` 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 `` has no end-of-route or feedback UI, no day/night styles, no road name label, and doesn't show reroutes as such. +- `` 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. diff --git a/docs/navigation/rn-navigation-view.md b/docs/navigation/rn-navigation-view.md index e850b170..ce535b5a 100644 --- a/docs/navigation/rn-navigation-view.md +++ b/docs/navigation/rn-navigation-view.md @@ -9,14 +9,17 @@ description: "A customizable turn-by-turn navigation UI written in React Native `` is a turn-by-turn navigation UI written in React Native on top of the [headless API](getting-started.md), on an `@rnmapbox/maps` navigation map. It looks the same on iOS and Android. Use it as is, or copy [its source](https://github.com/rnmapbox/navigation/blob/main/src/RNNavigationView.tsx) as a starting point for your own UI. RNNavigationView during simulated guidance on iOS +RNNavigationView arrival card in night appearance -In `0.1.0-alpha.1` it shows: +It shows: -- a maneuver banner with the next instruction, the distance to it, and the lanes; +- a maneuver banner with the next instruction, the distance to it, road shields, exit numbers and the lanes; - the speed limit sign (US or Vienna style) and the current road name; - arrival time, remaining time and distance; - mute, overview/recenter and end buttons; -- an arrival message at the final destination. +- an arrival card with the destination name and an end button. + +With `waypoints` it also requests alternative routes. Navigation maps draw them, and tapping one switches guidance to it, which `addRouteChangeListener` reports with `reason: 'alternative'`. ```tsx import { RNNavigationView } from '@rnmapbox/navigation'; @@ -38,10 +41,12 @@ import { RNNavigationView } from '@rnmapbox/navigation'; It takes the same props as [``](navigation-view.md#props) (`route` or `waypoints`, `simulate`, `mute`, `onRouteProgress`, `onArrive`, `onCancel`, `onError`, `style`, `testID`), plus: -| Prop | Type | Description | -| ---------- | ----------- | ------------------------------------------------------------------------ | -| `styleURL` | `string` | Map style. Defaults to Mapbox Standard. | -| `children` | `ReactNode` | Rendered inside its `MapView`, e.g. extra sources and layers. | +| 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. | +| `styleURL` | `string` | Map style. Defaults to Mapbox Standard. With another style, `appearance` only changes the UI. | +| `children` | `ReactNode` | Rendered inside its `MapView`, e.g. extra sources and layers. | See [`RNNavigationViewProps`](api/Components/RNNavigationViewProps.md) in the API reference. @@ -51,18 +56,4 @@ Like ``, it uses the app's single navigation session: mounting i It reads the headless events (route progress, location, camera state, off-route, arrival), so your own `Navigation.add…Listener` subscriptions keep working alongside it. -## Next release - -:::info Not released yet -These are on the `main` branch of [rnmapbox/navigation](https://github.com/rnmapbox/navigation) ([#10](https://github.com/rnmapbox/navigation/pull/10)) and not part of `0.1.0-alpha.1`. -::: - -RNNavigationView arrival card in night appearance - -- Road shields and exit numbers in the maneuver banner, from new `maneuverComponents` and `secondaryComponents` in route progress events. -- `distanceUnit` prop, `'metric'` or `'imperial'`, for the distances the view shows and the voice instructions of a route it requests through `waypoints`. It defaults to the new `Navigation.getDefaultDistanceUnit()`, from the device's region and measurement settings. -- Alternative routes: with `waypoints` the view requests them, navigation maps draw them, and tapping one switches guidance to it, reported by `addRouteChangeListener` with `reason: 'alternative'`. -- `appearance` prop, `'auto'` (default), `'day'` or `'night'`. `'auto'` switches at sunrise and sunset at the user's location; the UI and the Standard style's light preset follow it. -- An arrival card with the destination name and an end button. - Road shields come from the Directions API's shield images, not the Mapbox designed shields the native banners use. diff --git a/docs/navigation/troubleshooting.md b/docs/navigation/troubleshooting.md index e2786b6b..ca39208c 100644 --- a/docs/navigation/troubleshooting.md +++ b/docs/navigation/troubleshooting.md @@ -40,11 +40,11 @@ post_install do |installer| end ``` -The `@rnmapbox/navigation` Expo config plugin already adds this. [rnmapbox/maps#4376](https://github.com/rnmapbox/maps/pull/4376) fixes it in `@rnmapbox/maps` itself; once you're on a release with it, the snippet is redundant but harmless. +[rnmapbox/maps#4376](https://github.com/rnmapbox/maps/pull/4376) fixes it in `@rnmapbox/maps` 10.3.16, the minimum version `@rnmapbox/navigation` 0.1.0 supports, so you only see this error with an older `@rnmapbox/maps`; upgrading it fixes the error too. The `@rnmapbox/navigation` Expo config plugin also adds the path; with both, it appears once. ## iOS: Swift package resolution error for MapboxMaps -Navigation SDK 3.N pins Maps SDK 11.N exactly, and `@rnmapbox/maps`' package requirement (`$RNMapboxMapsVersion`, default `~> 11.23.1`) must allow it. With a different Navigation SDK version, set `$RNMapboxMapsVersion = '= 11.N.x'` to match. +Navigation SDK 3.N pins Maps SDK 11.N exactly, and `@rnmapbox/maps`' package requirement (`$RNMapboxMapsVersion`, default `~> 11.33.0`) must allow it. With a different Navigation SDK version, set `$RNMapboxMapsVersion = '= 11.N.x'` to match. ## Android: Maps version resolution conflict @@ -59,7 +59,7 @@ Cannot find a version of 'com.mapbox.maps:android' that satisfies the version co ```groovy buildscript { ext { - RNMapboxMapsVersion = '11.23.1' // matches Navigation SDK 3.23.1 + RNMapboxMapsVersion = '11.33.0' // matches Navigation SDK 3.33.0 } } ``` @@ -70,7 +70,7 @@ Both libraries pick the `-ndk27` artifacts with `targetSdkVersion` 35 or higher. ## iOS: assertion about UIBackgroundModes audio -`` crashes in a debug build with an assertion from the Navigation SDK's voice controller about the `audio` background mode. Add it to `Info.plist`: +Guidance crashes in a debug build, as soon as it starts, with an assertion from the Navigation SDK's voice controller about the `audio` background mode. The Expo config plugin adds it unless `backgroundAudio` is `false`. In a bare app, add it to `Info.plist`: ```xml UIBackgroundModes @@ -79,4 +79,4 @@ Both libraries pick the `-ndk27` artifacts with `targetSdkVersion` 35 or higher. ``` -With Expo, add `"UIBackgroundModes": ["audio"]` to `ios.infoPlist` in `app.json` and run `npx expo prebuild` again. +With Expo, remove `"backgroundAudio": false` from the `@rnmapbox/navigation` plugin options, or add `"UIBackgroundModes": ["audio"]` to `ios.infoPlist` in `app.json`, and run `npx expo prebuild` again.