簡體   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