googlemaps / googlemaps/react-native-navigation-sdk
iOS: travel mode is lost when setDestinations runs before the NavigationView attaches, route computes as driving
- Dominant language
- TypeScript
- Stars
- 227
- Forks
- 38
- Avg merge
- 5d 7h
- Merged PRs (30d)
- 10
Description
### Is there an existing issue for this?
- [x] I have searched the existing issues
### Description of the bug
On iOS, the `travelMode` passed to `setDestinations` (in `routingOptions` or `routeTokenOptions`) is only applied to the `GMSMapView` of each `NavigationView` registered at that instant. It is never set on the `GMSNavigationSession`, whose navigator computes the route and whose `travelMode` defaults to driving.
When `setDestinations` runs before the `NavigationView` has attached to the session, the mode is lost and the route is computed as a driving route. This is the normal state for the first request after a launch in an app that mounts the `NavigationView` in the same React commit that starts guidance: the native view is created and registered, but `attachToNavigationSessionIfNeeded` only runs on its first non-zero layout, so the value set on the not-yet-attached map view never reaches the session.
Calling `setDestinations` again once the view is attached returns the correct route, which is why "change the travel mode and change it back" works around it.
Android is not affected: the mode travels inside `RoutingOptions` on every request.
### iOS Platform
- [x] iOS
### Android Platform
- [ ] Android
### React Native version
0.86.3
### React version
19.2.8
### Package version
0.17.1 (the code is unchanged on `main` at 0.17.2)
### Native SDK versions
iOS GoogleNavigation 11.1.0, Android navigation 7.9.0 (as pinned by the package)
### Steps to reproduce
1. Cold launch an app that renders a `MapView` on its home screen and swaps it for a `NavigationView` when a destination is chosen, calling `setDestinations(..., {routingOptions: {travelMode: TravelMode.CYCLING}})` from an effect in that same render.
2. Call `startGuidance()`.
3. Read `getCurrentTimeAndDistance()` or look at the route.
4. Change the travel mode and call `setDestinations` again with the view now attached.
### Expected vs Actual Behavior
Expected: the first route honours `TravelMode.CYCLING`.
Actual: the first route is a driving route. On a ~20 km test route (Montreal downtown to YUL, iPhone 17 Pro simulator, iOS 26.4) the first request returned 18.2 km in 46 min with `delaySeverity: 2`, which only driving routes carry; an explicit cycling request on the attached view returned 29.7 km in 96 min with `delaySeverity: 0`, and walking 18.6 km in 4 h 20. With the fix in the linked pull request the first request returns the 29.6 km / 96 min cycling route.
### Code Sample
```ts
// Rendered as soon as a destination is chosen; NavigationView mounts in this same commit.
useEffect(() => {
if (!destination || !isNavigationInitialized) return;
navigationController.setDestinations([{title: destination.name, position: destination}], {
routingOptions: {travelMode: TravelMode.CYCLING, avoidHighways: true},
displayOptions: {showDestinationMarkers: true},
}).then(() => navigationController.startGuidance());
}, [destination, isNavigationInitialized]);
```
### Additional Context
`NavModule.mm` `configureNavigatorWithTravelMode:` forwards to `[NavViewModule setTravelMode:]`, which loops over `viewControllersRegistry` and calls `[_mapView setTravelMode:]`. `GMSNavigationSession` exposes its own `travelMode` property and it is never written. The fix is to set it there before updating the views, and to have a view that attaches later copy the session's mode.
Contributor guide
Assessment
This issue has not been assessed yet.