繁体   English   中英

谷歌地图 iOS SDK,获取两个地点之间的路线

[英]Google Maps iOS SDK, Getting Directions between 2 locations

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

1.) 使用URL Scheme,需要在您的设备上安装Google Maps App。

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

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

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

谢谢,

    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 Direction API Sdk 在您的 google 开发者控制台中启用。

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

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

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

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

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)

        })

斯威夫特 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 中。

我已经这样做了,因为它还在地图上用DIRECTION ROUTE显示引脚距离和持续时间。 但不要忘记在您的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);
}];

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

}
(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;

 }

如果有人想解析与路由数组的距离,则以下是在 swift 4/5 中获取距离的方法

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

正如@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 ),忽略所有其他不需要的属性和结构就完全没points

您现在可以做的是要求JSONDecoderGMSDirectionsResponse从正文数据中解码GMSDirectionsResponse 在我的项目中,我使用了Moya,但我相信您也可以使用URLSessiondata对象来实现。

// 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 下标成员和大量[]大括号混淆。 😊

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

如果您使用的是受限密钥,则必须将X-Ios-Bundle-Identifier header 添加到您将密钥限制到的包中。 对于 header,它也适用于 Postman。 在此处输入图像描述

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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