Closed nastasiupta closed 2 years ago
/cc @Udumft
Hi! route
is now a readonly property due to updates to the use an indexed route response as a source of routing information. Route can now be updated by a method call on a router or navigation service as shown here.
Also, if you are implementing your own reroute generation method, consider implementing it as a custom RoutingProvider
as a designed way to do so. You can see this short example on how to do it.
@Udumft As I saw in the exemple you don't use func navigationViewController(_ navigationViewController: NavigationViewController, shouldRerouteFrom location: CLLocation) -> Bool {
method. Also, you don't set the delegate for NavigationViewController.
I noticed that the functions from the custom object are not called. Is this because I use the delegate?
In my case I still need the delegate method to update the custom bottom view, using this method func navigationViewController(_ navigationViewController: NavigationViewController, didUpdate progress: RouteProgress, with location: CLLocation, rawLocation: CLLocation) {
Maybe snapshot for using navigation view controller will help to understand my setup: `
private func startNavigationWith(coordinates: [CLLocationCoordinate2D], completion: (() -> Void)?) {
let matchOptions = NavigationMatchOptions(coordinates: coordinates, profileIdentifier: .automobile)
matchOptions.includesSteps = true
matchOptions.waypointIndices = IndexSet([0, coordinates.count - 1])
matchOptions.distanceMeasurementSystem = .imperial
Directions.shared.calculate(matchOptions) { [weak self] (_, result) in
switch result {
case .failure(let error):
LoadingIndicator.hide {
UIAlertController.show(title: .serverError, message: .custom(error.localizedDescription))
}
case .success(let matchResponse):
guard let strongSelf = self else {
return
}
do {
let routingResponse = try RouteResponse(matching: matchResponse, options: matchOptions, credentials: NavigationSettings.shared.directions.credentials)
let routeOptions = NavigationRouteOptions(navigationMatchOptions: matchOptions)
let responseOptions = ResponseOptions.route(routeOptions)
// This is to replace responseOptions from match to route
let routingResponse2 = RouteResponse(httpResponse: routingResponse.httpResponse, routes: routingResponse.routes, waypoints: routingResponse.waypoints, options: responseOptions, credentials: NavigationSettings.shared.directions.credentials)
guard let route = routingResponse2.routes?.first, let _ = route.legs.first else {
LoadingIndicator.hide(animated: false) {
UIAlertController.show(title: .serverError, message: .custom("Can't start route"))
}
return
}
let navigationService = MapboxNavigationService(routeResponse: routingResponse2,
routeIndex: 0,
routeOptions: routeOptions,
customRoutingProvider: strongSelf.customRoutingProvider,
credentials: NavigationSettings.shared.directions.credentials,
simulating: .onPoorGPS)
let containerViewController = UIViewController.instantiate(type: .navigationBottomView) as? ContainerViewController
let instructionsCardCollection = InstructionsCardViewController()
let navigationOptions = NavigationOptions(styles: [MotourNavigationDayStyle(), MotourNavigationNightStyle()], navigationService: navigationService, topBanner: instructionsCardCollection, bottomBanner: containerViewController)
let navigationViewController = NavigationViewController(navigationService: navigationService)
strongSelf.navigationViewController = navigationViewController
navigationViewController.navigationOptions = navigationOptions
navigationViewController.showsReportFeedback = false
navigationViewController.modalPresentationStyle = .fullScreen
navigationViewController.showsSpeedLimits = true
// navigationViewController.navigationView.speedLimitView
navigationViewController.delegate = strongSelf
navigationViewController.navigationMapView?.delegate = strongSelf
navigationViewController.showsEndOfRouteFeedback = false
if let navigationBottomView = containerViewController as? NavigationBottomView {
strongSelf.navigationBottomView = navigationBottomView
navigationBottomView.setup(progress: navigationViewController.navigationService.routeProgress)
navigationBottomView.setup(state: strongSelf.state)
navigationBottomView.delegate = strongSelf
}
let indexedRouteResponse = IndexedRouteResponse(routeResponse: routingResponse, routeIndex: 0)
navigationViewController.navigationService.router.updateRoute(with: indexedRouteResponse, routeOptions: routeOptions, completion: nil)
LoadingIndicator.hide(animated: false) {
strongSelf.parentViewController?.present(navigationViewController, animated: true)
completion?()
}
strongSelf.setupProgressUpdates()
} catch {
LoadingIndicator.hide {
UIAlertController.show(title: .serverError, message: .serverError)
}
}
}
}
}
`
Linked example illustrates a different approach in case you are looking for overriding a reroute calculation. If you are not - using updateRoute
will do what you are trying to achieve by attempting to update route
property.
@Udumft
func navigationViewController(_ navigationViewController: NavigationViewController, shouldRerouteFrom location: CLLocation) -> Bool {
guard isRerouting == false,
let rideType = rideType,
let navigatedRouteIndex = navigatedRouteIndex,
navigatedRouteIndex < rideType.schedule.routes.count else { return false }
isRerouting = true
func handle(locations: [MLocation]) {
mapBoxRouteEntityConvertorWorker.execute(data: locations) { [weak self] _, routeResponse in
guard let strongSelf = self else { return }
strongSelf.isRerouting = false
if let routeResponse = routeResponse {
navigationViewController.navigationService.router.updateRoute(with: IndexedRouteResponse(routeResponse: routeResponse, routeIndex: 0), routeOptions: nil, completion: nil)
}
}
}
let route = rideType.schedule.routes[navigatedRouteIndex]
rawRouteDetectorWorker.execute(data: .init(start: MLocation(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude), destination: route.destinationPlace.location, options: route.options, wayType: route.wayType)) { [weak self] error, locations in
guard let strongSelf = self else { return }
if let locations = locations, locations.count > 0 {
handle(locations: locations)
} else {
strongSelf.rawRouteDetectorWorker.execute(data: .init(start: MLocation(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude), destination: route.destinationPlace.location, options: [], wayType: .fastest)) { [weak self] error, locations in
guard let strongSelf = self else { return }
if let locations = locations, locations.count > 0 {
handle(locations: locations)
} else {
strongSelf.isRerouting = false
}
}
}
}
return false
}
This should solve the issue? returning false in this function and using the navigationViewController.navigationService.router.updateRoute function?
It looks like you are trying to provide your own reroute instead of a default calculated one. Your snippet will get it done, but you can also achieve it by following the example. Providing your route in this method will result in SDK treating this route as usual reroute, continuing the usual rerouting pipeline. Just make sure to set your custom RoutingProvider
to related navigation service.
Mapbox Navigation SDK version
2.5.1
Steps to reproduce
Trigger rerouting function
func navigationViewController(_ navigationViewController: NavigationViewController, shouldRerouteFrom location: CLLocation) -> Bool {
Generate a new Route object, using your custom algorithm to (locations from current user location to destination)
Assign the new Route object to NavigationViewController
navigationViewController.navigationService.route = route Cannot assign to property: 'route' is a get-only property
On older SDK versions it worked just to assign the new Route object to existing NavigationViewController NavigationService, but with the new SDK version is not working anymore. How can this behavior be achieved again?Expected behavior
Just assign the new Route object to NavigationViewController and the SDK is doing it's job. It worked like that before.
Actual behavior
I get this error right now: Cannot assign to property: 'route' is a get-only property
Is this a one-time issue or a repeatable issue?
repeatable