Objective-C: рисуем маршрут используя Google Map API

Screen Shot 2017-04-24 at 23.43.20

В этот раз мы получим текущее местоположение пользователя и нарисуем путь до точки назначения на Google карте. Для использования карты мы воспользуемся одним API и для получения координат линии маршрута — другим API.

Шаг 1.

Вначале надо получить API ключ. Вы можете сразу же создать проект и получить ключ по этой ссылке: Google console.

Screen Shot 2017-04-24 at 11.14.26

Screen Shot 2017-04-24 at 11.15.40

 

Вы получите строку содержащую латинские буквы и цифры. В моем случае длина ключа составила 39 символов.

Шаг 2.

Создаем проект, добавляем разрешение на получение местоположения в Info.plist.

Screen Shot 2017-04-25 at 15.15.08

Шаг 3.

Добавляем GoogleMaps pod.

Screen Shot 2017-04-25 at 15.33.50

Пост по теме: Как добавить pod?

Шаг 4.

UILabel *mapStatusLabel;
GMSMapView *mapView;
UITextField *destinationField;
CLLocationManager *locationManager;
CLLocationCoordinate2D coordinate;

- (void)viewDidLoad {
    [super viewDidLoad];
    [self buildView];
}

- (void) buildView {
    CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
    
    UIView *containerView = [[UIView alloc] initWithFrame:CGRectMake(
                                                                          0,
                                                                          0,
                                                                          screenWidth,
                                                                          550)];
    containerView.layer.borderColor = [UIColor grayColor].CGColor;
    containerView.layer.borderWidth = 1.0f;
    [self.view addSubview:containerView];
    
    CGFloat currentY = 20;
    
    mapStatusLabel = [[UILabel alloc] initWithFrame:CGRectMake(
                                                                 30,
                                                                 currentY,
                                                                 containerView.frame.size.width - 60,
                                                                 20)];
    mapStatusLabel.text = @"Let me determine your location";
    mapStatusLabel.textAlignment = NSTextAlignmentCenter;
    [containerView addSubview:mapStatusLabel];
    currentY += mapStatusLabel.frame.size.height + 10;
    
    UIButton *getMyLocationButton = [[UIButton alloc] initWithFrame:CGRectMake(
                                                                             (screenWidth - 200)/2,
                                                                             currentY,
                                                                             200,
                                                                             30)];
    [getMyLocationButton setTitle:@"Get my location" forState:UIControlStateNormal];
    getMyLocationButton.showsTouchWhenHighlighted = true;
    getMyLocationButton.backgroundColor = [UIColor grayColor];
    [getMyLocationButton addTarget:self action:@selector(getMyLocation:) forControlEvents:UIControlEventTouchUpInside];
    [containerView addSubview:getMyLocationButton];
    currentY += getMyLocationButton.frame.size.height + 10;
    
    destinationField = [[UITextField alloc] initWithFrame:CGRectMake(
                                                                                  (screenWidth - 200)/2,
                                                                                  currentY,
                                                                                  200,
                                                                                  30)];
    destinationField.layer.borderColor = [UIColor grayColor].CGColor;
    destinationField.layer.borderWidth = 1.0f;
    [containerView addSubview:destinationField];
    currentY += destinationField.frame.size.height + 10;
    
    UIButton *drawRoute = [[UIButton alloc] initWithFrame:CGRectMake(
                                                                     (screenWidth - 200)/2,
                                                                     currentY,
                                                                     200,
                                                                     30)];
    [drawRoute setTitle:@"Draw route destination" forState:UIControlStateNormal];
    drawRoute.showsTouchWhenHighlighted = true;
    drawRoute.backgroundColor = [UIColor grayColor];
    [drawRoute addTarget:self action:@selector(drawRoute:) forControlEvents:UIControlEventTouchUpInside];
    [containerView addSubview:drawRoute];
    currentY += drawRoute.frame.size.height + 10;
   
    [GMSServices provideAPIKey:@"[API_KEY]"];
    
    mapView = [[GMSMapView alloc] initWithFrame:CGRectMake(
                                                              10,
                                                              currentY,
                                                              containerView.frame.size.width - 20,
                                                              300)];
    mapView.backgroundColor = [UIColor grayColor];
    [containerView addSubview:mapView];
}

Вы получите подобное отображение:

Screen Shot 2017-04-24 at 23.43.06

Шаг 5.

Получить геолокацию пользователя.

- (void) getMyLocation:(UIButton *) sender {
    NSLog(@"getMyLocation");
    
    mapStatusLabel.text = @"Determining location";
    
    locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self;
    locationManager.distanceFilter = kCLDistanceFilterNone;
    locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
    [locationManager requestWhenInUseAuthorization];
    [locationManager startUpdatingLocation];
}

- (void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
    NSLog(@"didUpdateLocations");

    mapStatusLabel.text = @"Your location found";
    coordinate = locations.lastObject.coordinate;
    
    GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:coordinate.latitude longitude:coordinate.longitude zoom:4];
    mapView.camera = camera;
    
    [locationManager stopUpdatingLocation];
}

При нажатии на кнопку «Get my location» мы запускаем location manager, благодаря чему периодическу получаем местоположение пользователя в методе didUpdateLocations. Мне нужно получить координаты лишь однажды, поэтому в том же методе останавливаю location manager.

После получения координаты устанавливаем камеру на это место.

Шаг 6.

Для получения маршрута используем Google Directions API. В документации написано, что надо обязательно вставлять API ключ, но запрос проходит и без него (Апрель 2017). В любом случае добавим в запрос API ключ.

- (void) drawRoute:(UIButton *) sender {
    NSLog(@"drawRoute");
    
    mapStatusLabel.text = @"Drawing route";
    [mapView clear];
   
    [self fetchPolylineWithDestination:destinationField.text];
}

- (void)fetchPolylineWithDestination:(NSString *)destinationString
{
    NSString *originString = [NSString stringWithFormat:@"%f,%f", coordinate.latitude, coordinate.longitude];
    NSString *destinationEncodedString = [destinationString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    NSString *directionsAPI = @"https://maps.googleapis.com/maps/api/directions/json?";
    NSString *directionsUrlString = [NSString stringWithFormat:@"%@&origin=%@&destination=%@&mode=driving&key=[API_KEY]", directionsAPI, originString, destinationEncodedString];
    NSURL *directionsUrl = [NSURL URLWithString:directionsUrlString];
    
    NSURLSessionDataTask *fetchDirectionsTask = [[NSURLSession sharedSession] dataTaskWithURL:directionsUrl completionHandler:
        ^(NSData *data, NSURLResponse *response, NSError *error) {
            NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
            
            dispatch_sync(dispatch_get_main_queue(), ^{
                if (error) {
                    mapStatusLabel.text = @"Drawing route failed";
                    NSLog(@"error: %@", error);
                    return;
                }
                
                NSArray *routesArray = [json objectForKey:@"routes"];
                
                GMSPolyline *polyline = nil;
                if ([routesArray count] > 0) {
                    NSDictionary *routeDict = [routesArray objectAtIndex:0];
                    NSDictionary *routeOverviewPolyline = [routeDict objectForKey:@"overview_polyline"];
                    NSString *points = [routeOverviewPolyline objectForKey:@"points"];
                    GMSPath *path = [GMSPath pathFromEncodedPath:points];
                    polyline = [GMSPolyline polylineWithPath:path];
                }
                
                if(polyline)
                    polyline.map = mapView;
                mapStatusLabel.text = @"Drawing route completed";
                
            });
        }];
    [fetchDirectionsTask resume];
}

В fetchPolylineWithDestination мы делаем запрос в API и получаем координаты маршрута в JSON формате. Точка отбытия — местоположение пользователя, точка назначения — место, введенное в текстовом поле. Как базу я использовал метод написанный Tarek-ом на stackoverflow и внес корректировки.

Шаг 7.

Результат:

Screen Shot 2017-04-24 at 23.43.20

Screen Shot 2017-04-24 at 23.42.23

Проект на GitHub.

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Картинка профиля Doszhan Kalibek

Doszhan Kalibek