【问题标题】:Google Maps iOS SDK, Getting Directions between 2 locationsGoogle Maps iOS SDK,获取 2 个位置之间的路线
【发布时间】:2014-01-21 05:59:33
【问题描述】:

当我使用 Google Maps SDK 时,我试图在 iOS 上获取两个位置之间的行车方向。我知道我们可以使用两种方法来做到这一点:-

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

2.) 使用 Directions API,通过请求-响应,然后解析 JSON。显示标记以显示方向。

现在,我的问题是我可以通过其他方式在 iOS 上执行此操作吗?我需要显示从我当前位置到我有纬度/经度的特定位置的方向。

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

谢谢,

【问题讨论】:

    标签: ios xcode google-maps cocoa-touch google-maps-sdk-ios


    【解决方案1】:
        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 开发者控制台中启用您的 Google Direction API Sdk。

    【讨论】:

    • 在阅读了 Google Doc for Map iOS 之后,我回到这里并得到一个易于理解的示例:D
    • 这就是我要找的,你是天才,你好久不见了,
    • @muhammad Noman 这个 api 不起作用。它说在服务器端实现,因为客户端使用私钥不安全。
    • 当您将其用于 IOS 应用程序时,请确保将 Google API 限制设置为:否则它将限制您的 IP 权限
    • 如何使用ASIHTTPRequest
    【解决方案2】:

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

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

    【讨论】:

    • 谢谢,我猜你是对的,这就是我目前所发现的!
    • 添加到 Brett 的答案,看看 Google Dev Live 演示如何做到这一点。 youtube.com/watch?v=AdV7bCWuDYg
    【解决方案3】:

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

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

    【讨论】:

    • 谢谢你是对的,但我得到了答案,实际上它不可能在你的应用程序中显示方向。 Google Maps SDK iOS,无法在应用内显示方向。
    【解决方案4】:

    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】:

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

      在这里,你需要将你的key(google api key)添加到上面的API中。

      【讨论】:

      • 谢谢,GMSPath 部分非常有帮助——不过请注意:我不建议强制展开,而是定义一个包含尽可能多字段的可编码结构(也许你也想解析路线的步骤?)然后让JSONDecoder 尝试为您从响应中解码对象。使用 Moya / Alamofire 时特别​​容易。
      • @mmika1000,谢谢。我对 JSONDecoder 没有任何想法,可以发布您更新的代码吗?它可以对其他人有所帮助...
      • 你是对的,为什么不 - 刚刚发布,看看 :)
      【解决方案6】:

      我已经这样做了,因为它还在地图上用 DIRECTION ROUTE 显示 PINS DISTANCE AND DURATION。但不要忘记在您的 GOOGLE 开发者控制台

      中将您的 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);
      }];
      

      【讨论】:

      • 只是为了澄清@PatelJigar的解决方案中的'_sourceAdd'和'_destinationAdd'参数可以是以下格式:origin=24+Sussex+Drive+Ottawa+ON, origin=41.43206,-81.38992, origin= place_id:ChIJ3S-JXmauEmsRUcIaWtf4MzE 参考:developers.google.com/maps/documentation/directions/…
      【解决方案7】:

      使用 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()
      
      }
      

      【讨论】:

      • 兄弟我也在做同样的事情,但折线没有画出来..你能帮帮我吗
      • 你能解释一下你的意思吗?上述方法检索从 A 到 B 的距离,不要在地图上画线。在此处发布详细问题和链接
      • 这不能回答问题
      • 我需要这个,非常感谢,但是我用 alamofire 和 swiftyjson 来做这个
      【解决方案8】:
      (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;
      
       }
      

      【讨论】:

        【解决方案9】:

        如果有人想从路线数组中解析距离,那么以下是快速获取距离的方法 4/5

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

        【讨论】:

          【解决方案10】:

          正如@iOS 所建议的,我还将发布我的答案,向您展示如何使用 Codable 和 Alamofire/Moya 来完成它。

          为此,您必须改造 GoogleMaps 响应实体,如下所示:

          /// 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 的data 对象。

          // 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")
          }
          

          这可能看起来像一大堆代码,但它非常方便,它可以让您避免弄乱 JSON 下标成员和大量 [] 大括号。 ?

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

          【讨论】:

            【解决方案11】:

            在谷歌开发者控制台中创建一个密钥,确保你的项目是使用 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);
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2014-01-24
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多