Mapbox Navigation in iOS with in my mapView controller
Asked Answered
L

2

7

I want to integrate Mapbox navigation in iOS, I can easily get the direction/route between two coordinate also to get the navigation path from mapbox we can use below code

let options = NavigationOptions(styles: nil)
let viewController = NavigationViewController(for: self.directionsRoute!)
viewController.delegate=self    
self.present(viewController, animated: true, completion: nil)

But the problem is I want to display the navigation in my mapview which is a part of another view controller, I can do that by getting a direction/route and instruction but I can't find any method which will be called every second so that I can update route instruction, as well as route, in case of user change the path.

Let me know if I am missing anything or any changes needed.

-Thanks in advance

Laryngeal answered 1/8, 2019 at 12:37 Comment(0)
B
1

here is my approach:

  • first i did get only directions instructions from the MapBox api taking advantage of it's free API calls quota and draw the instructions on GMSMapView or MapKit taking advantage of their good performance and memory management.

  • podfile

pod 'MapboxDirections.swift'
import MapboxDirections

this is done through the below code

  • have the property for MapBox directions
@IBOutlet weak var googleMapView: GMSMapView!
let locationManager = CLLocationManager()
let mapBoxirections = Directions(accessToken: osmToken)
var path: GMSMutablePath?
  • then do the actual api call
private func drawRouteBetween(source: StopModel, destination: StopModel) {

        guard let name = source.name, let lat = source.latitude, let lng = source.longitude else { return }
        guard let nameDest = destination.name, let latDest = destination.latitude, let lngDest = destination.longitude else { return }

        let waypoints = [
            Waypoint(coordinate: CLLocationCoordinate2D(latitude: lat, longitude: lng), name: name),
            Waypoint(coordinate: CLLocationCoordinate2D(latitude: latDest, longitude: lngDest), name: nameDest),
            ]
        let options = RouteOptions(waypoints: waypoints, profileIdentifier: .automobile)
        options.includesSteps = true
        options.distanceMeasurementSystem = .metric

        mapBoxirections.calculate(options) { (waypoints, routes, error) in
            guard error == nil else {
                print("Error calculating directions: \(error!)")
                return
            }

            if let route = routes?.first, let leg = route.legs.first {

                for step in leg.steps {
                    if let coordinates = step.coordinates {
                        for (index, point) in coordinates.enumerated() {
                            let source = point
                            if index <= coordinates.count - 2 {
                                let destination = coordinates[index + 1]
                                self.drawPolyLine(source: source, destination: destination)
                            }
                        }
                    }
                }

            }
        }

    }
  • note that StopModel is my custom made CLLocation so feel free to replace it with your own as long it has the latitude and longitude

  • create the method that draws Polyline on your CLLocationManagerDelegate as below

private func drawPolyLine(source: CLLocationCoordinate2D, destination: CLLocationCoordinate2D){
        path?.add(source)
        path?.add(destination)
        let polyLine = GMSPolyline(path: path)
        polyLine.strokeWidth = 4 // width of your choice
        polyLine.strokeColor = .red // color of your choice 
        polyLine.map = googleMapView
    }
  • then take a look at the MapBoxDirections.Route model and explore it's properties you will find very useful info inside it

and then take advantage of the callback function from the GMS Delegate that notifies you with the location update instead having a timer and calling it every second this is more efficient way

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        /* do your business here */
    }
  • do not forget to have the delegate of the location manager to self or the class of your choice
Benzaldehyde answered 7/8, 2019 at 9:41 Comment(0)
P
0

Maybe this helps a bit: you can easily add observer for route progress changes:

NotificationCenter.default.addObserver(self,
                                       selector: #selector(progressDidChange(notification:)),
                                       name: .routeControllerProgressDidChange,
                                       object: navigationService.router)

You need a navigation service with your route by creating it like

let navigationService = MapboxNavigationService(route: route)

The function progressDidChange can do something like:

@objc func progressDidChange(notification: NSNotification) {
    guard let routeProgress = notification.userInfo?[RouteControllerNotificationUserInfoKey.routeProgressKey] as? RouteProgress,
        let location = notification.userInfo?[RouteControllerNotificationUserInfoKey.locationKey] as? CLLocation else {
        return
    }

    // you have all information you probably need in routeProgress, f.E.
    let secondsRemaining = routeProgress.currentLegProgress.currentStepProgress.durationRemaining

    ...
}
Plasma answered 5/8, 2019 at 12:16 Comment(1)
Thanks but the issue is RouteProgress method is not being calledLaryngeal

© 2022 - 2024 — McMap. All rights reserved.