mapbox-navigation-ios icon indicating copy to clipboard operation
mapbox-navigation-ios copied to clipboard

[Bug]: The route is displayed for less than a second and then disappears from the map view

Open Gustavo-Shotl opened this issue 3 years ago • 12 comments
trafficstars

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

Gustavo-Shotl avatar Mar 07 '22 12:03 Gustavo-Shotl

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?

jill-cardamon avatar Mar 09 '22 18:03 jill-cardamon

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

Gustavo-Shotl avatar Mar 11 '22 07:03 Gustavo-Shotl

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?

ShanMa1991 avatar Mar 11 '22 22:03 ShanMa1991

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

Gustavo-Shotl avatar Mar 15 '22 15:03 Gustavo-Shotl

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?

ShanMa1991 avatar Mar 16 '22 19:03 ShanMa1991

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.

Gustavo-Shotl avatar Mar 21 '22 10:03 Gustavo-Shotl

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.

ShanMa1991 avatar Mar 22 '22 23:03 ShanMa1991

@Gustavo-Shotl, are you still able to reproduce this issue with v2.4.0?

MaximAlien avatar Apr 18 '22 18:04 MaximAlien

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 avatar Apr 25 '22 13:04 Gustavo-Shotl

@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 avatar Apr 27 '22 11:04 bamx23

@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 avatar Apr 27 '22 14:04 Gustavo-Shotl

@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

bamx23 avatar Apr 27 '22 15:04 bamx23