mapbox-navigation-ios
mapbox-navigation-ios copied to clipboard
[Bug]: The route is displayed for less than a second and then disappears from the map view
Mapbox Navigation SDK version
2.3
Steps to reproduce
After fetching a route using
Directions.shared.calculate(options) { [weak self] (session, result) in
switch result {
case .failure(let error):
debuggie("Mapbox calculate error: \(error)")
case .success(let response):
guard let self = self, let route = response.routes?.first else { return }
self.handleFetched(route: route)
}
}
}
I handle the route with the following method
func handleFetched(route: Route) {
navigationViewController?.navigationMapView?.show([route], legIndex: 0)
navigationViewController?.navigationMapView?.showWaypoints(on: route)
}
The route appears on the map but instantly disappears.
Expected behavior
A new route appears without disappearing on the navigation map view
Actual behavior
A new route appears on the navigation map view but disappears instantly
Is this a one-time issue or a repeatable issue?
repeatable
Hi @Gustavo-Shotl! Thanks for reporting. Could you give a bit more info about this behavior? Does the route line always disappear? Was this a fresh start or did it happen after starting active navigation/rerouting?
Hollo @jill-cardamon. Thanks for replying
Does the route line always disappear? Yes It does
Was this a fresh start or did it happen after starting active navigation/rerouting?
The route always disappears when is displayed using the navigationViewController?.navigationMapView?.show([route], legIndex: 0) of the iOS Mapbox Navigation SDK. The route is displayed in the map but then after 1 second or less it disappears
Hi @Gustavo-Shotl , is it during the active navigation after the navigationViewController already been presented, or is it for previewing mode? If it's for previewing mode, would you try to create a NavigationMapView to show the map, and then call the navigationMapView.show([route], legIndex: 0) to show the route line?
Hello @ShanMa1991
It is during the active navigation, after the navigationViewController has been presented. I currently don't use preview because this app at the moment is 100% UIKit.
I will attach a video where the issue is visible
https://user-images.githubusercontent.com/75128007/158409726-f2b947e3-a116-497a-88e8-97ba1d888f51.mp4
Hi @Gustavo-Shotl , I'm thinking that maybe your navigationViewController is not correctly initialized. We need to create a MapboxNavigationService based on the RouteResponse and RouteOptions as well as the SimulationMode. Then we create a NavigationViewController based on the NavigationService. As in our Example, once the NavigationViewController is correctly created and presented, it would load the view and automatically start navigation with the waypoints and route line shown by default.
Another possible cause is that when we present the navigationViewController for navigation, we need to nil out the navigationMapView from previewing mode. Would you check that?
Hello @ShanMa1991
We initialize the NavigationViewController as the tutorial says. We create an instance of MapboxNavigationService which we use in the initializer NavigationViewController(for:routeIndex:routeOptions:navigationOptions:) along with the corresponding options. Below I put the code that initialize the NavigationViewController
Directions.shared.calculate(options) { [weak self] (session, result) in
switch result {
case .failure(let error):
print(error)
case .success(let response):
guard let self = self else { return }
let navigationService = MapboxNavigationService(routeResponse: response,
routeIndex: 0,
routeOptions: options,
simulating: self.currentSimulationMode)
let navigationOptions = NavigationOptions(navigationService: navigationService)
self.navigationViewController = NavigationViewController(for: response,
routeIndex: 0,
routeOptions: options,
navigationOptions: navigationOptions)
self.configureNavigationController()
}
}
func configureNavigationController() {
navigationViewController?.delegate = self
navigationViewController?.showsReportFeedback = false
navigationViewController?.routeLineTracksTraversal = true
navigationViewController?.navigationService.locationManager.startUpdatingHeading()
addChildViewController(self.navigationViewController, inView: self.view)
}
And regarding the preview mode, I don't understand how it can be affecting since our application is 100% UIKit. Could it be a compatibility issue?
As additional information, when I had the 1.4 version of the SDK, this problem did not happen, but when I updated to 2.3 this problem appeared.
Hi @Gustavo-Shotl I tried to reproduce this issue but failed with v2.3.0. So the code I use to reproduce this issue as following:
MapboxRoutingProvider().calculateRoutes(options: options) { [weak self] (session, result) in
switch result {
case .failure(let error):
print(error)
case .success(let response):
guard let routes = response.routes, !routes.isEmpty, case let .route(options) = response.options else { return }
guard let self = self, let route = response.routes?.first else { return }
let navigationService = MapboxNavigationService(routeResponse: response,
routeIndex: 0,
routeOptions: options,
simulating: .always)
let navigationOptions = NavigationOptions(navigationService: navigationService)
let navigationViewController = NavigationViewController(for: response,
routeIndex: 0,
routeOptions: options,
navigationOptions: navigationOptions)
navigationViewController.delegate = self
navigationViewController.showsReportFeedback = false
navigationViewController.routeLineTracksTraversal = true
navigationViewController.navigationService.locationManager.startUpdatingHeading()
navigationViewController.navigationMapView?.show([route], legIndex: 0) // Could be removed because active navigation will automatically show the route that currently driving on.
navigationViewController.navigationMapView?.showWaypoints(on: route)
self.present(navigationViewController, animated: true) {
self.navigationMapView = nil
}
}
}
So we could see that the navigation starts and the route is shown on the map. Because I cannot reproduce this issue, I think the cause of this issue may be that the route you want to display is different from the current route that you're driving on. According to the following:
https://github.com/mapbox/mapbox-navigation-ios/blob/27d662deac54c6d9e274f631ca50e5df1c37eeed/Sources/MapboxNavigation/NavigationMapView.swift#L218-L219
We automatically show the current route that the user is driving on during active navigation through NavigationViewController.navigationMapView. show (_: legIndex:), and it will remove the previous routes. If the route or route leg you want to display before starting the navigation is different from the current one, it will be removed.
If you want to show several different routes, you could display them through NavigationMapView directly for previewing, before we start the active navigation through the NavigationViewController.
@Gustavo-Shotl, are you still able to reproduce this issue with v2.4.0?
Hello @MaximAlien @ShanMa1991
Yes, I have updated the SDK to 2.4.0 and the issue is still happening. When I use self.navigationViewController?.navigationMapView?.show(routes) the issue doesn't happen but when I use the self.navigationViewController?.navigationMapView?.show(routes, legIndex: 0) the issue happens
It seems that the problem could be some difference in the implementation of both methods.
@Gustavo-Shotl just to clarify, when we say "preview mode" it's not about SwiftUI, it's about the mode of the app when you don't have a route guidance session but rather just showing a map where you can preview routes to the user before starting such a guidance session. When there is no route guidance you should use NavigationMapView. Using this map view you can show different routes to the user. When you want to start active route guidance you need to create a MapboxNavigationService and NavigationViewController with a specific route.
Do you try to show a route in the NavigationMapView within NavigationViewController that is different from what NavigationViewController and MapboxNavigationService were initially created with?
@bamx23 We use a pseudo-route (equal origin and destiny) in order to create and present the MapBox NavigationViewController
@objc func createNavigationViewController() {
guard let location = locationManager?.lastLocation?.coordinate else {
Timer.scheduledTimer(timeInterval: 2.0,
target: self,
selector: #selector(createNavigationViewController),
userInfo: nil,
repeats: false)
return
}
let origin = Waypoint(coordinate: location)
let destiny = Waypoint(coordinate: location)
let routeOptions = NavigationRouteOptions(waypoints: [origin, destiny])
Directions.shared.calculate(routeOptions) { [weak self] (session, result) in
switch result {
case .failure(let error):
print(error.localizedDescription)
case .success(let response):
guard let self = self else { return }
self.navigationViewController = NavigationViewController(for: response, routeIndex: 0, routeOptions: routeOptions)
self.navigationViewController?.showsReportFeedback = false
self.navigationViewController?.routeLineTracksTraversal = true
self.addChildViewController(self.navigationViewController, inView: self.view)
}
}
}
Then our app listens for new events and updates the route with the following code
func calculateRoute(to destiny: CLLocationCoordinate2D) {
guard let userLocation = navigationViewController?.navigationMapView?.mapView.location.latestLocation?.location else {
return
}
let userWaypoint = Waypoint(location: userLocation)
userWaypoint.heading = userLocation.course
userWaypoint.headingAccuracy = 90
userWaypoint.allowsArrivingOnOppositeSide = false
let destinyWaypoint = Waypoint(coordinate: destiny)
let routeOptions = NavigationRouteOptions(waypoints: [userWaypoint, destinyWaypoint])
routeOptions.includesSteps = true
Directions.shared.calculate(routeOptions) { [weak self] (session, result) in
switch result {
case .failure(let error):
print(error.localizedDescription)
case .success(let response):
guard let self = self, let routes = response.routes, let route = routes.first else { return }
self.navigationViewController?.navigationMapView?.show(routes, legIndex: 0)
self.navigationViewController?.navigationMapView?.showWaypoints(on: route)
}
}
}
We call the first block of code only when we create the NavigationViewController, but the second block of code is called every time we receive a new target coordinate from our back-end modules.
The issue is that when the second block of code is called, the route is shown but only for 1 second and then it disappears (this does not happen for example with the destination marker)
@Gustavo-Shotl to update route in NavigationViewController please use this method:
let indexedRouteResponse = IndexedRouteResponse(routeResponse: response, routeIndex: 0)
self.navigationViewController?.navigationService.router.updateRoute(with: indexedRouteResponse,
routeOptions: routeOptions,
completion: nil)
show and showWaypoints are the methods that work for a standalone NavigationMapView. NavigationViewController manages the current route itself based on the NavigationService.
Also, make sure you need NavigationViewController (i.e. you need active guidance along this route). Also, significant updates to the active route during a guidance session with NavigationViewController might affect your billing. See this docs page: Pricing - Active Guidance trip