Google Maps iOS SDK,获取2个地点之间的路线

时间:2014-01-03 14:25:27

标签: ios google-maps google-maps-sdk-ios

当我使用谷歌地图SDK时,我正试图在iOS上的两个位置之间获得驾驶方向。我知道我们可以使用两种方法来做到这一点: -

1。)使用URL Scheme,您的设备上必须安装Google Maps App。

2。)使用Directions API,通过Request-Response然后解析JSON。显示标记以显示方向。

现在,我的问题还有其他方法可以在iOS上执行此操作吗?我需要显示从当前位置到我有Lat / Long的特定位置的方向。

我的意思是,真的不可能简单地传递2个位置作为参数和Google Maps SDK,会给我指示吗?

谢谢,

11 个答案:

答案 0 :(得分:44)

    NSString *urlString = [NSString stringWithFormat:
                       @"%@?origin=%f,%f&destination=%f,%f&sensor=true&key=%@",
                       @"https://maps.googleapis.com/maps/api/directions/json",
                       mapView.myLocation.coordinate.latitude,
                       mapView.myLocation.coordinate.longitude,
                       destLatitude,
                       destLongitude,
                       @"Your Google Api Key String"];
NSURL *directionsURL = [NSURL URLWithString:urlString];


ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:directionsURL];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
    NSString *response = [request responseString];
    NSLog(@"%@",response);
    NSDictionary *json =[NSJSONSerialization JSONObjectWithData:[request responseData] options:NSJSONReadingMutableContainers error:&error];
    GMSPath *path =[GMSPath pathFromEncodedPath:json[@"routes"][0][@"overview_polyline"][@"points"]];
    GMSPolyline *singleLine = [GMSPolyline polylineWithPath:path];
    singleLine.strokeWidth = 7;
    singleLine.strokeColor = [UIColor greenColor];
    singleLine.map = self.mapView;
}
else NSLog(@"%@",[request error]);

注意:确保您的Google Directions API Sdk在您的Google开发者控制台中启用。

答案 1 :(得分:19)

听起来您正在寻找像谷歌地图应用程序用于显示路线的UI Chrome。适用于iOS的Google Maps SDK会为您绘制地图,但您需要负责额外的导航镶边。

您可以使用Google Directions API来请求路线,然后使用服务返回的编码路径,使用GMSPolyline方法绘制GMSPath's pathFromEncodedPath:

答案 2 :(得分:13)

这些线显示给定纬度/经度与用户位置之间的位置;

NSString *googleMapUrlString = [NSString stringWithFormat:@"http://maps.google.com/?saddr=%f,%f&daddr=%@,%@", mapView.userLocation.coordinate.latitude, mapView.userLocation.coordinate.longitude, destinationLatitude, destinationLongtitude];

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:googleMapUrlString]];

答案 3 :(得分:8)

我已经完成了它,因为它还在地图上显示 DIRECTION ROUTE PINS DISTANCE AND DURATION 。但不要忘记在 GOOGLE DEVELOPER CONSOLE

中设置 GOOGLE DIRECTION API启用
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);
}];

答案 4 :(得分:8)

Swift 3.0& XCode 8.0 使用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)

        })

答案 5 :(得分:3)

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()

在这里,您需要将密钥(Google api密钥)添加到上述API。

答案 6 :(得分:1)

(void)viewDidLoad {
    [super viewDidLoad];

    GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:30.692408
                                                            longitude:76.767556
                                                                 zoom:14];
    GMSMapView *mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
    mapView.myLocationEnabled = YES;

    // Creates  markers in the center of the map.


    GMSMarker *marker = [[GMSMarker alloc] init];
    marker.position = CLLocationCoordinate2DMake(30.6936659,  76.77201819999999);
    marker.title = @"Chandigarh 47c";
    marker.snippet = @"Hello World";
    marker.map = mapView;

    GMSMarker *marker1 = [[GMSMarker alloc] init];
    marker1.position = CLLocationCoordinate2DMake(30.742138,  76.818756);
    marker1.title = @"Sukhna Lake";
    marker1.map = mapView;
    //creating a path

    GMSMutablePath *path = [GMSMutablePath path];
    [path addCoordinate:CLLocationCoordinate2DMake(@(30.6936659).doubleValue,@(76.77201819999999).doubleValue)];
    [path addCoordinate:CLLocationCoordinate2DMake(@(30.742138).doubleValue,@(76.818756).doubleValue)];

    GMSPolyline *rectangle = [GMSPolyline polylineWithPath:path];
    rectangle.strokeWidth = 2.f;
    rectangle.map = mapView;
    self.view=mapView;

 }

答案 7 :(得分:0)

在Google开发者控制台中创建一个密钥,确保您的项目是使用App bundleID创建的,然后添加以下代码

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);

答案 8 :(得分:0)

如果有人希望解析距路由数组的距离,可以通过以下方法快速获取距离4/5

let distance = responseJSON["routes"][0]["legs"][0]["distance"]["text"]

答案 9 :(得分:0)

正如@iOS所建议的那样,我还将发布答案,以向您展示如何使用Codable和Alamofire / Moya来实现这一目标的方法。

为此,您必须像这样重塑GoogleMaps Response实体:

/// 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?
}


您可以看到响应对象如何由路由数组和状态字符串(例如"OK")组成。每条路线都具有一些属性,包括overview_polyline字段。为了能够用JSONDecoder解码该对象,您还需要对该类建模(它只包含键points的字符串值。

现在,如果您只需要overview_polyline,那么只要您仍对响应的层次结构建模(例如GMSDirectionsResponse> GMSRoute> OverviewPolyline> points,就可以省略所有其他不需要的属性和结构,这是完全可以的。 )。

您现在可以做的是要求JSONDecoder用一行代码从正文数据中解码GMSDirectionsResponse!在我的项目中,我使用了Moya,但是我敢肯定您也可以使用URLSession的{​​{1}}对象来实现它。

data

这可能看起来像是大量的代码,但它非常方便,它使您避免弄乱JSON下标成员和许多// 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") } 大括号。 ?

如果您有任何疑问,我们很乐意为您提供帮助!

答案 10 :(得分:-1)

使用 Swift 我肯定以这种方式解决了。
我的目的是找到两个坐标之间的距离:

import AFNetworking 

/**
 Calculate distance between two valid coordinates

 - parameter origin:      origin coordinates
 - parameter destination: destination coordinates
 - parameter completion:  completion callback
 */
func calculateDistance(origin origin: CLLocation, destination: CLLocation, completion: (distance: Double?) -> Void) {

    let service = "https://maps.googleapis.com/maps/api/directions/json"
    let originLat = origin.coordinate.latitude
    let originLong = origin.coordinate.longitude
    let destLat = destination.coordinate.latitude
    let destLong = destination.coordinate.longitude
    let urlString = "\(service)?origin=\(originLat),\(originLong)&destination=\(destLat),\(destLong)&mode=driving&units=metric&sensor=true&key=<YOUR_KEY>"
    let directionsURL = NSURL(string: urlString)

    let request = NSMutableURLRequest(URL: directionsURL!)

    request.HTTPMethod = "GET"
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.addValue("application/json", forHTTPHeaderField: "Accept")
    let operation = AFHTTPRequestOperation(request: request)
    operation.responseSerializer = AFJSONResponseSerializer()

    operation.setCompletionBlockWithSuccess({ (operation: AFHTTPRequestOperation!, responseObject: AnyObject!) -> Void in

        if let result = responseObject as? NSDictionary {
            if let routes = result["routes"] as? [NSDictionary] {
                if let lines = routes[0]["overview_polyline"] as? NSDictionary {
                    if let points = lines["points"] as? String {
                        let path = GMSPath(fromEncodedPath: points)
                        let distance = GMSGeometryLength(path)
                        print("wow \(distance / 1000) KM")

                    }
                }
            }
        }
        }) { (operation: AFHTTPRequestOperation!, error: NSError!)  -> Void in
            print("\(error)")
    }

    operation.start()

}