Google Maps iOS SDK, Getting Directions between 2 locations

前端 未结 11 1259
栀梦
栀梦 2020-12-02 07:52

While I am using Google Maps SDK, I am trying to get driving direction between two locations on iOS. I know we can do this using two methods:-

1.) Using URL Scheme,

相关标签:
11条回答
  • 2020-12-02 08:38

    Swift 4.1, Xcode 9.4.1

    //Here you need to set your origin and destination points and mode 
    let url = NSURL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=Machilipatnam&destination=Vijayawada&mode=driving")
    
    //OR if you want to use latitude and longitude for source and destination
    //let url = NSURL(string: "\("https://maps.googleapis.com/maps/api/directions/json")?origin=\("17.521100"),\("78.452854")&destination=\("15.1393932"),\("76.9214428")")
    
            let task = URLSession.shared.dataTask(with: url! as URL) { (data, response, error) -> Void in
    
                do {
                    if data != nil {
                        let dic = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableLeaves) as!  [String:AnyObject]
    //                        print(dic)
    
                        let status = dic["status"] as! String
                        var routesArray:String!
                        if status == "OK" {
                            routesArray = (((dic["routes"]!as! [Any])[0] as! [String:Any])["overview_polyline"] as! [String:Any])["points"] as! String
    //                            print("routesArray: \(String(describing: routesArray))")
                        }
    
                        DispatchQueue.main.async {
                            let path = GMSPath.init(fromEncodedPath: routesArray!)
                            let singleLine = GMSPolyline.init(path: path)
                            singleLine.strokeWidth = 6.0
                            singleLine.strokeColor = .blue
                            singleLine.map = mapView
                        }
    
                    }
                } catch {
                    print("Error")
                }
            }
    
            task.resume()
    

    Here, you need to add your key (google api key) to the above API.

    0 讨论(0)
  • 2020-12-02 08:43

    Swift 3.0 & XCode 8.0 Using AFNetworking & SwiftJson

            let destLatitude="26.9124"
            let destLongitude="75.7873"
            mapView.isMyLocationEnabled = true
            var urlString = "\("https://maps.googleapis.com/maps/api/directions/json")?origin=\("28.7041"),\("77.1025")&destination=\(destLatitude),\(destLongitude)&sensor=true&key=\("Your-Api-key")"
    
            urlString = urlString.addingPercentEncoding( withAllowedCharacters: .urlQueryAllowed)!
    
            let manager=AFHTTPRequestOperationManager()
    
            manager.responseSerializer = AFJSONResponseSerializer(readingOptions: JSONSerialization.ReadingOptions.allowFragments) as AFJSONResponseSerializer
    
            manager.requestSerializer = AFJSONRequestSerializer() as AFJSONRequestSerializer
    
            manager.responseSerializer.acceptableContentTypes = NSSet(objects:"application/json", "text/html", "text/plain", "text/json", "text/javascript", "audio/wav") as Set<NSObject>
    
    
            manager.post(urlString, parameters: nil, constructingBodyWith: { (formdata:AFMultipartFormData!) -> Void in
    
                }, success: {  operation, response -> Void in
                    //{"responseString" : "Success","result" : {"userId" : "4"},"errorCode" : 1}
                    //if(response != nil){
                    let parsedData = JSON(response)
                    print_debug("parsedData : \(parsedData)")
                   var path = GMSPath.init(fromEncodedPath: parsedData["routes"][0]["overview_polyline"]["points"].string!)
                     //GMSPath.fromEncodedPath(parsedData["routes"][0]["overview_polyline"]["points"].string!)
                    var singleLine = GMSPolyline.init(path: path)
                    singleLine.strokeWidth = 7
                    singleLine.strokeColor = UIColor.green
                    singleLine.map = self.mapView
                    //let loginResponeObj=LoginRespone.init(fromJson: parsedData)
    
    
                    //  }
                }, failure: {  operation, error -> Void in
    
                    print_debug(error)
                    let errorDict = NSMutableDictionary()
                    errorDict.setObject(ErrorCodes.errorCodeFailed.rawValue, forKey: ServiceKeys.keyErrorCode.rawValue as NSCopying)
                    errorDict.setObject(ErrorMessages.errorTryAgain.rawValue, forKey: ServiceKeys.keyErrorMessage.rawValue as NSCopying)
    
            })
    
    0 讨论(0)
  • 2020-12-02 08:45

    Create a key in google developer console make sure your project is created with App bundleID after that add the following code

    NSString *KEY=@"";
    NSString *Origin=@"";
    NSString *Destination=@"";
    NSString *str_maps=[NSString stringWithFormat:@"https://maps.googleapis.com/maps/api/directions/json?origin=%@&destination=%@&key=%@",Origin,Destination,KEY];
    NSURL *url=[NSURL URLWithString:str_maps];
     NSData *dta=[NSData dataWithContentsOfURL:url];
    NSDictionary *dict=(NSDictionary *)[NSJSONSerialization JSONObjectWithData:dta options:kNilOptions error:nil];
    NSLog(@"%@",dict);
    
    0 讨论(0)
  • 2020-12-02 08:49

    As @iOS suggested I'm also posting my answer to show you a way how to accomplish it using Codable and Alamofire/Moya.

    To do so, you'd have to remodel the GoogleMaps Response entities, like so:

    /// Struct for modelling a response from the Google Maps Directions API. This is the "root level"
    struct GMSDirectionsResponse: Codable {
        /// The suggested routes
        let routes: [GMSRoute]
        /// Status telling if request was okay
        let status: String
    }
    /// Struct for modelling a Route suggested by GoogleMaps Directions API.
    struct GMSRoute: Codable {
        /// Represents an area in the map
        struct Bounds: Codable {
            // You can omit these structs for your case. 
            // Just to give an idea how it would look like if you model the entire response
            // ...
        }
        
        struct Leg: Codable {
            // ...
        }
        
        /// A single step of a route
        struct Step: Codable {
            // ...
        }
        
        /// Structure around the coded representation of the GMSPath
        struct OverviewPolyline: Codable {
            /// A coded representation of the GMSPath
            let points: String
        }
        
        /// The bounds to show on the map to include the whole route
        let bounds: Bounds?
        /// All legs of this route, including the single steps
        let legs: [Leg]?
        /// The path to walk/drive/etc. this route
        let overview_polyline: OverviewPolyline?
        /// A textual summary of the most important roads to take
        let summary: String?
    }
    
    
    

    You can see how a response object consists of an array of routes and a status string (e.g. "OK"). Each route has a few properties again, including the overview_polyline field. For being able to have that object decoded by a JSONDecoder you also need to model that class (it simply contains a string value for the key points.

    Now if you only need the overview_polyline it's perfectly fine to omit all other unneeded properties and structs as long as you still model the hierarchical structure of the response (e.g. GMSDirectionsResponse > GMSRoute > OverviewPolyline > points).

    What you can do now is to ask a JSONDecoder to decode a GMSDirectionsResponse from the body data with a single line! In my project I used Moya but I'm sure you can also do it with URLSession's data object.

    // let moya do request
    let moya = MoyaProvider<YourGMSService>()
    moya.request(.getDirections(origin: origin, destination: destination)) { (result) in
        switch result {
        case .success(let response):
            // check if request was successful
            if
                // makes sure status is code is 2xx
                (try? response.filterSuccessfulStatusCodes()) != nil,
                // this line tries to decode a GMSDirectionsResponse object from response.data
                let directions = try? JSONDecoder().decode(GMSDirectionsResponse.self, from: response.data)
            {
                // successful request, converted response to JSON Dictionary
                NSLog("GET DIRECTIONS: Success")
                
                // here we can check for the directions properites already!
                NSLog("GoogleMaps Directions request finished with status %@", directions.status)
                
                // check if we have at least one GMSRoute with an overview_polyline
                guard let encodedPath = directions.routes.first?.overview_polyline else { return }
                // now let's use the encoded path:
                DispatchQueue.main.async {
                    let path = GMSPath.init(fromEncodedPath: encodedPath.points)
                    
                    // continue as in other answers (Y)
                    let singleLine = GMSPolyline.init(path: path)
                    singleLine.strokeWidth = 6.0
                    singleLine.strokeColor = .blue
                    singleLine.map = mapView
                }
                return
            }
            // some error handling if we couldn't parse the data to a GMSDirectionsResponse object
            NSLog("Could not parse JSON from Directions API Response:\n%@", response.debugDescription)
        case .failure(let error):
            // we had an error
            NSLog(error.localizedDescription)
        }
        // log and complete with nil
        NSLog("GET DIRECTIONS: Failed")
    }
    

    This might look like a huge load of code but it's totally convenient and it keeps you from messing around with JSON subscript members and lots of [] braces.

    0 讨论(0)
  • 2020-12-02 08:51

    I had done it as it also shows PINS DISTANCE AND DURATION on map with DIRECTION ROUTE. But dont forget to set your GOOGLE DIRECTION API TO ENABLED in your GOOGLE DEVELOPER CONSOLE

    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    [manager.requestSerializer setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
    
    NSString *urlString =@"https://maps.googleapis.com/maps/api/directions/json";
    
     NSDictionary *dictParameters = @{@"origin" : [NSString stringWithFormat:@"%@",_sourceAdd], @"destination" : [NSString stringWithFormat:@"%@",_destinationAdd], @"mode" : @"driving", @"key":@"AIzaSyD9cWTQkAxemELVXTNUCALOmzlDv5b9Dhg"};
    
    [manager GET:urlString parameters:dictParameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
    
    
        GMSPath *path =[GMSPath pathFromEncodedPath:responseObject[@"routes"][0][@"overview_polyline"][@"points"]];
        NSDictionary *arr=responseObject[@"routes"][0][@"legs"];
        NSMutableArray *loc=[[NSMutableArray alloc]init];
    
        loc=[[arr valueForKey:@"start_location"]valueForKey:@"lat"];
        _sourceloc.latitude=[loc[0] doubleValue];
    
        loc=[[arr valueForKey:@"start_location"]valueForKey:@"lng"];
        _sourceloc.longitude=[loc[0] doubleValue];
    
        loc=[[arr valueForKey:@"end_location"]valueForKey:@"lat"];
        _destinationloc.latitude=[loc[0] doubleValue];
    
        loc=[[arr valueForKey:@"end_location"]valueForKey:@"lng"];
        _destinationloc.longitude=[loc[0] doubleValue];
    
    
        NSString *dis,*dur;
        loc=[[arr valueForKey:@"distance"]valueForKey:@"text"];
        dis=loc[0];
    
        loc=[[arr valueForKey:@"duration"]valueForKey:@"text"];
        dur=loc[0];
    
    
        NSString *sa,*da;
        loc=[arr valueForKey:@"start_address"];
        sa=loc[0];
    
        loc=[arr valueForKey:@"end_address"];
        da=loc[0];
    
        UIAlertView *av=[[UIAlertView alloc]initWithTitle:@"Route Info" message:[NSString stringWithFormat:@"Distance:%@ \nDuration:%@",dis,dur] delegate:nil cancelButtonTitle:@"Okay" otherButtonTitles:nil, nil];
        [av show];
    
    
    
        GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:_sourceloc.latitude  longitude:_sourceloc.longitude zoom:10];
        mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
    
        GMSMarker *marker = [GMSMarker markerWithPosition:_sourceloc];
        marker.title=@"Source";
        marker.snippet =sa;
        marker.appearAnimation = kGMSMarkerAnimationPop;
        marker.map = mapView;
    
    
        GMSMarker *marker2 = [GMSMarker markerWithPosition:_destinationloc];
        marker2.title=@"Destination";
        marker2.snippet =da;
        marker2.appearAnimation = kGMSMarkerAnimationPop;
        marker2.map = mapView;
    
        GMSPolyline *singleLine = [GMSPolyline polylineWithPath:path];
        singleLine.strokeWidth = 4;
        singleLine.strokeColor = [UIColor blueColor];
        singleLine.map = mapView;
    
        self.view = mapView;
    
    
    
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"Error: %@", error);
    }];
    
    0 讨论(0)
提交回复
热议问题