简体   繁体   中英

How to draw routes between two locations in google maps iOS swift

I'm using google maps in my iOS swift project. I want to draw a path between two locations on the map (Not straight line). Any idea how to do that ?

To draw polyline between two locations on Google Map in Swift.

//Pass your source and destination coordinates in this method.

func fetchRoute(from source: CLLocationCoordinate2D, to destination: CLLocationCoordinate2D) {
    
    let session = URLSession.shared
    
    let url = URL(string: "http://maps.googleapis.com/maps/api/directions/json?origin=\(source.latitude),\(source.longitude)&destination=\(destination.latitude),\(destination.longitude)&sensor=false&mode=driving")!
    
    let task = session.dataTask(with: url, completionHandler: {
        (data, response, error) in
        
        guard error == nil else {
            print(error!.localizedDescription)
            return
        }
        
        guard let jsonResult = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any], let jsonResponse = jsonResult else {
            print("error in JSONSerialization")
            return
        }
        
        guard let routes = jsonResponse["routes"] as? [Any] else {
            return
        }
        
        guard let route = routes[0] as? [String: Any] else {
            return
        }

        guard let overview_polyline = route["overview_polyline"] as? [String: Any] else {
            return
        }
        
        guard let polyLineString = overview_polyline["points"] as? String else {
            return
        }
        
        //Call this method to draw path on map
        self.drawPath(from: polyLineString)
    })
    task.resume()
}

To draw polyline on map .

func drawPath(from polyStr: String){
    let path = GMSPath(fromEncodedPath: polyStr)
    let polyline = GMSPolyline(path: path)
    polyline.strokeWidth = 3.0
    polyline.map = mapView // Google MapView
}

Showing Multiple-routes between two locations in google maps in swift 3.0 with camera zoom :

    let origin = "\(startLocation.coordinate.latitude),\(startLocation.coordinate.longitude)"
    let destination = "\(destinationLocation.coordinate.latitude),\(destinationLocation.coordinate.longitude)"

    let urlString = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving&key=API_KEY"

    let url = URL(string: urlString)
    URLSession.shared.dataTask(with: url!, completionHandler: {
        (data, response, error) in
        if(error != nil){
            print("error")
        }else{
            do{
                let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [String : AnyObject]
                let routes = json["routes"] as! NSArray
                self.mapView.clear()

                OperationQueue.main.addOperation({
                    for route in routes
                    {
                        let routeOverviewPolyline:NSDictionary = (route as! NSDictionary).value(forKey: "overview_polyline") as! NSDictionary
                        let points = routeOverviewPolyline.object(forKey: "points")
                        let path = GMSPath.init(fromEncodedPath: points! as! String)
                        let polyline = GMSPolyline.init(path: path)
                        polyline.strokeWidth = 3

                        let bounds = GMSCoordinateBounds(path: path!)
                        self.mapView!.animate(with: GMSCameraUpdate.fit(bounds, withPadding: 30.0))

                        polyline.map = self.mapView

                    }
                })
            }catch let error as NSError{
                print("error:\(error)")
            }
        }
    }).resume()

Above all answers can draw routes but there is a way that you can draw accurate route using directions API.Here is the code hopefully it will help for you.

func getRouteSteps(from source: CLLocationCoordinate2D, to destination: CLLocationCoordinate2D) {

    let session = URLSession.shared

    let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(source.latitude),\(source.longitude)&destination=\(destination.latitude),\(destination.longitude)&sensor=false&mode=driving&key=\(Your_API_Key)")!

    let task = session.dataTask(with: url, completionHandler: {
        (data, response, error) in

        guard error == nil else {
            print(error!.localizedDescription)
            return
        }

        guard let jsonResult = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any] else {

            print("error in JSONSerialization")
            return

        }



        guard let routes = jsonResult["routes"] as? [Any] else {
            return
        }

        guard let route = routes[0] as? [String: Any] else {
            return
        }

        guard let legs = route["legs"] as? [Any] else {
            return
        }

        guard let leg = legs[0] as? [String: Any] else {
            return
        }

        guard let steps = leg["steps"] as? [Any] else {
            return
        }
          for item in steps {

            guard let step = item as? [String: Any] else {
                return
            }

            guard let polyline = step["polyline"] as? [String: Any] else {
                return
            }

            guard let polyLineString = polyline["points"] as? String else {
                return
            }

            //Call this method to draw path on map
            DispatchQueue.main.async {
                self.drawPath(from: polyLineString)
            }

        }
    })
    task.resume()
}

And then

    //MARK:- Draw Path line
func drawPath(from polyStr: String){
    let path = GMSPath(fromEncodedPath: polyStr)
    let polyline = GMSPolyline(path: path)
    polyline.strokeWidth = 3.0
    polyline.map = mapView // Google MapView


    let cameraUpdate = GMSCameraUpdate.fit(GMSCoordinateBounds(coordinate: sourceLocationCordinates, coordinate: destinationLocationCordinates))
    mapView.moveCamera(cameraUpdate)
    let currentZoom = mapView.camera.zoom
    mapView.animate(toZoom: currentZoom - 1.4)
}

Note: I have added sourcesLocationCordinates and destinationLocationCordinates variables.Don't forget to replace them with your source and destination.Hopefully this will help you making perfect route line.

Create a new Swift file copy this code, that's it call then drawPolygon() method from map view for polygon line.

import GoogleMaps

private struct MapPath : Decodable{
    var routes : [Route]?
}

private struct Route : Decodable{ 
    var overview_polyline : OverView?
}

private struct OverView : Decodable {
    var points : String?
}

extension GMSMapView {

    //MARK:- Call API for polygon points

    func drawPolygon(from source: CLLocationCoordinate2D, to destination: CLLocationCoordinate2D){

        let config = URLSessionConfiguration.default
        let session = URLSession(configuration: config)

        guard let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(source.latitude),\(source.longitude)&destination=\(destination.latitude),\(destination.longitude)&sensor=false&mode=driving") else {
            return
        }

        DispatchQueue.main.async {

            session.dataTask(with: url) { (data, response, error) in

                guard data != nil else {
                    return
                }
                do {

                    let route = try JSONDecoder().decode(MapPath.self, from: data!)

                    if let points = route.routes?.first?.overview_polyline?.points {
                        self.drawPath(with: points)
                    }
                    print(route.routes?.first?.overview_polyline?.points)

                } catch let error {

                    print("Failed to draw ",error.localizedDescription)
                }
                }.resume()
            }
    }

    //MARK:- Draw polygon

    private func drawPath(with points : String){

        DispatchQueue.main.async {

            let path = GMSPath(fromEncodedPath: points)
            let polyline = GMSPolyline(path: path)
            polyline.strokeWidth = 3.0
            polyline.strokeColor = .red
            polyline.map = self

        }
    }
}

This piece of code will work right for you. Don't forget to change your API key and mode (walking, driving).

func draw(src: CLLocationCoordinate2D, dst: CLLocationCoordinate2D){

    let config = URLSessionConfiguration.default
    let session = URLSession(configuration: config)

    let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(src.latitude),\(src.longitude)&destination=\(dst.latitude),\(dst.longitude)&sensor=false&mode=walking&key=**YOUR_KEY**")!

    let task = session.dataTask(with: url, completionHandler: {
        (data, response, error) in
        if error != nil {
            print(error!.localizedDescription)
        } else {
            do {
                if let json : [String:Any] = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any] {

                    let preRoutes = json["routes"] as! NSArray
                    let routes = preRoutes[0] as! NSDictionary
                    let routeOverviewPolyline:NSDictionary = routes.value(forKey: "overview_polyline") as! NSDictionary
                    let polyString = routeOverviewPolyline.object(forKey: "points") as! String

                    DispatchQueue.main.async(execute: {
                        let path = GMSPath(fromEncodedPath: polyString)
                        let polyline = GMSPolyline(path: path)
                        polyline.strokeWidth = 5.0
                        polyline.strokeColor = UIColor.green
                        polyline.map = mapView    
                    })
                }

            } catch {
                print("parsing error")
            }
        }
    })
    task.resume()
}

Above all answers can draw routes but there is a way that you can draw accurate route using directions API.Here is the code hopefully it will help for you.

func getRouteSteps(from source: CLLocationCoordinate2D, to destination: CLLocationCoordinate2D) {

    let session = URLSession.shared

    let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(source.latitude),\(source.longitude)&destination=\(destination.latitude),\(destination.longitude)&sensor=false&mode=driving&key=\(Your_API_Key)")!

    let task = session.dataTask(with: url, completionHandler: {
        (data, response, error) in

        guard error == nil else {
            print(error!.localizedDescription)
            return
        }

        guard let jsonResult = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any] else {

            print("error in JSONSerialization")
            return

        }



        guard let routes = jsonResult["routes"] as? [Any] else {
            return
        }

        guard let route = routes[0] as? [String: Any] else {
            return
        }

        guard let legs = route["legs"] as? [Any] else {
            return
        }

        guard let leg = legs[0] as? [String: Any] else {
            return
        }

        guard let steps = leg["steps"] as? [Any] else {
            return
        }
          for item in steps {

            guard let step = item as? [String: Any] else {
                return
            }

            guard let polyline = step["polyline"] as? [String: Any] else {
                return
            }

            guard let polyLineString = polyline["points"] as? String else {
                return
            }

            //Call this method to draw path on map
            DispatchQueue.main.async {
                self.drawPath(from: polyLineString)
            }

        }
    })
    task.resume()
}

And then

    //MARK:- Draw Path line
func drawPath(from polyStr: String){
    let path = GMSPath(fromEncodedPath: polyStr)
    let polyline = GMSPolyline(path: path)
    polyline.strokeWidth = 3.0
    polyline.map = mapView // Google MapView

     let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let cameraUpdate = GMSCameraUpdate.fit(GMSCoordinateBounds(coordinate: appDelegate.userLocation!.coordinate, coordinate: CLLocationCoordinate2D(latitude: 55.7998428, longitude: -4.0420782)))
    mapView.moveCamera(cameraUpdate)
    let currentZoom = mapView.camera.zoom
    mapView.animate(toZoom: currentZoom - 1.4)
}

Hopefully this will help you making perfect route line.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM