Điều hướng một tuyến đường

Hãy làm theo hướng dẫn này để lập biểu đồ tuyến đường trong ứng dụng của bạn đến một đích đến duy nhất bằng cách sử dụng SDK Điều hướng cho iOS.

Tổng quan

  1. Tích hợp SDK Điều hướng vào ứng dụng của bạn, như mô tả trong phần Thiết lập dự án.
  2. Định cấu hình GMSMapView.
  3. Nhắc người dùng chấp nhận các điều khoản và điều kiện, đồng thời cho phép các dịch vụ vị trí và thông báo ở chế độ nền.
  4. Tạo một mảng chứa một hoặc nhiều đích đến.
  5. Xác định GMSNavigator để kiểm soát tính năng chỉ đường từng chặng.

Xem mã

/*
 * Copyright 2017 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import GoogleNavigation
import UIKit

class ViewController: UIViewController {

  var mapView: GMSMapView!
  var locationManager: CLLocationManager!

  override func loadView() {

    locationManager = CLLocationManager()

    // Set up the map view.
    let camera = GMSCameraPosition.camera(withLatitude: 47.67, longitude: -122.20, zoom: 14)
    mapView = GMSMapView.map(withFrame: .zero, camera: camera)

    // Show the terms and conditions.
    let companyName = "Ride Sharing Co."
    GMSNavigationServices.showTermsAndConditionsDialogIfNeeded(
      withCompanyName: companyName
    ) { termsAccepted in
      if termsAccepted {
        // Enable navigation if the user accepts the terms.
        self.mapView.isNavigationEnabled = true
        self.mapView.settings.compassButton = true

        // Request authorization to use location services.
        self.locationManager.requestAlwaysAuthorization()

        // Request authorization for alert notifications which deliver guidance instructions
        // in the background.
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert]) {
          granted, error in
          // Handle denied authorization to display notifications.
          if !granted || error != nil {
            print("User rejected request to display notifications.")
          }
        }
      } else {
        // Handle rejection of terms and conditions.
      }
    }

    view = mapView

    makeButton()
  }

  // Create a route and start guidance.
  func startNav() {
    var destinations = [GMSNavigationWaypoint]()
    destinations.append(
      GMSNavigationWaypoint.init(
        placeID: "ChIJnUYTpNASkFQR_gSty5kyoUk",
        title: "PCC Natural Market")!)
    destinations.append(
      GMSNavigationWaypoint.init(
        placeID: "ChIJJ326ROcSkFQRBfUzOL2DSbo",
        title: "Marina Park")!)

    mapView.navigator?.setDestinations(
      destinations
    ) { routeStatus in
      guard routeStatus == .OK else {
        print("Handle route statuses that are not OK.")
        return
      }
      self.mapView.navigator?.isGuidanceActive = true
      self.mapView.locationSimulator?.simulateLocationsAlongExistingRoute()
      self.mapView.cameraMode = .following
    }
  }

  // Add a button to the view.
  func makeButton() {
    // A button to start navigation.
    let navButton = UIButton(frame: CGRect(x: 5, y: 150, width: 200, height: 35))
    navButton.backgroundColor = .blue
    navButton.alpha = 0.5
    navButton.setTitle("Start navigation", for: .normal)
    navButton.addTarget(self, action: #selector(startNav), for: .touchUpInside)
    self.mapView.addSubview(navButton)
  }

}
/*
 * Copyright 2017 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#import "ViewController.h"
@import GoogleNavigation;

@interface ViewController ()
@end

@implementation ViewController {
  GMSMapView *_mapView;
  CLLocationManager *_locationManager;
}

- (void)loadView {

  _locationManager = [[CLLocationManager alloc] init];

  // Set up the map view.
  GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:47.67
                                                          longitude:-122.20
                                                               zoom:14];
  _mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];

  // Show the terms and conditions.
  NSString *companyName = @"Ride Sharing Co.";
  [GMSNavigationServices
    showTermsAndConditionsDialogIfNeededWithCompanyName:companyName
                                               callback:^(BOOL termsAccepted) {
     if (termsAccepted) {
       // Enable navigation if the user accepts the terms.
       _mapView.navigationEnabled = YES;
       _mapView.settings.compassButton = YES;

       // Request authorization to use the current device location.
       [_locationManager requestAlwaysAuthorization];

       // Request authorization for alert notifications which deliver guidance instructions
       // in the background.
       UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
       UNAuthorizationOptions options = UNAuthorizationOptionAlert;
       [center requestAuthorizationWithOptions:options
                             completionHandler:^(BOOL granted, NSError *_Nullable error) {
                               if (!error && granted) {
                                 NSLog(@"iOS Notification Permission: newly Granted");
                               } else {
                                 NSLog(@"iOS Notification Permission: Failed or Denied");
                               }
                             }];
     } else {
       // Handle rejection of the terms and conditions.
     }
   }];

  self.view = _mapView;

  [self makeButton];
}

// Create a route and initiate navigation.
- (void)startNav {
  NSArray<GMSNavigationWaypoint *> *destinations =
  @[[[GMSNavigationWaypoint alloc] initWithPlaceID:@"ChIJnUYTpNASkFQR_gSty5kyoUk"
                                             title:@"PCC Natural Market"],
    [[GMSNavigationWaypoint alloc] initWithPlaceID:@"ChIJJ326ROcSkFQRBfUzOL2DSbo"
                                             title:@"Marina Park"]];

  [_mapView.navigator setDestinations:destinations
                             callback:^(GMSRouteStatus routeStatus){
                               [_mapView.locationSimulator simulateLocationsAlongExistingRoute];
                               _mapView.navigator.guidanceActive = YES;
                               _mapView.navigator.sendsBackgroundNotifications = YES;
                               _mapView.cameraMode = GMSNavigationCameraModeFollowing;
                             }];
}

// Add a button to the view.
- (void)makeButton {
  // A button to start navigation.
  UIButton *navButton = [UIButton buttonWithType:UIButtonTypeCustom];
  [navButton addTarget:self
                action:@selector(startNav)
      forControlEvents:UIControlEventTouchUpInside];
  [navButton setTitle:@"Navigate" forState:UIControlStateNormal];
  [navButton setBackgroundColor:[UIColor blueColor]];
  navButton.frame = CGRectMake(5.0, 150.0, 100.0, 35.0);
  [_mapView addSubview:navButton];
}

@end

Nhắc người dùng cấp các quyền cần thiết

Trước khi sử dụng SDK chỉ đường, người dùng phải đồng ý với điều khoản và điều kiện, đồng thời cho phép sử dụng dịch vụ vị trí (đây là điều kiện bắt buộc để chỉ đường). Nếu chạy ở chế độ nền, ứng dụng của bạn cũng phải nhắc người dùng cho phép thông báo cảnh báo hướng dẫn. Phần này cho biết cách hiển thị lời nhắc uỷ quyền bắt buộc.

Uỷ quyền cho dịch vụ vị trí

SDK Điều hướng sử dụng các dịch vụ vị trí, yêu cầu người dùng uỷ quyền. Để bật dịch vụ vị trí và hiển thị hộp thoại uỷ quyền, hãy làm theo các bước sau:

  1. Thêm khoá NSLocationAlwaysUsageDescription vào Info.plist.
  2. Đối với giá trị này, hãy thêm nội dung giải thích ngắn gọn về lý do ứng dụng của bạn cần các dịch vụ vị trí. Ví dụ: "Ứng dụng này cần có quyền sử dụng dịch vụ vị trí để đi theo chỉ dẫn từng chặng."

  3. Để hiển thị hộp thoại uỷ quyền, hãy gọi requestAlwaysAuthorization() của thực thể trình quản lý vị trí.

self.locationManager.requestAlwaysAuthorization()

[_locationManager requestAlwaysAuthorization];

Uỷ quyền thông báo cảnh báo để hướng dẫn ở chế độ nền

SDK Điều hướng cần có quyền của người dùng để cung cấp thông báo cảnh báo khi ứng dụng đang chạy ở chế độ nền. Thêm mã sau đây để nhắc người dùng cấp quyền hiển thị các thông báo này:

UNUserNotificationCenter.current().requestAuthorization(options: [.alert]) {
  granted, error in
    // Handle denied authorization to display notifications.
    if !granted || error != nil {
      print("User rejected request to display notifications.")
    }
}

// Request authorization for alert notifications.
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
UNAuthorizationOptions options = UNAuthorizationOptionAlert;
[center requestAuthorizationWithOptions:options
                      completionHandler:
 ^(
   BOOL granted,
   NSError *_Nullable error) {
     if (!error && granted) {
       NSLog(@"iOS Notification Permission: newly Granted");
     } else {
       NSLog(@"iOS Notification Permission: Failed or Denied");
     }
   }];

Chấp nhận điều khoản và điều kiện

Sử dụng mã sau để hiển thị hộp thoại điều khoản và điều kiện, đồng thời bật tính năng điều hướng khi người dùng chấp nhận các điều khoản. Xin lưu ý rằng ví dụ này bao gồm mã cho dịch vụ vị trí và thông báo cảnh báo hướng dẫn (đã hiển thị trước đó).

  let termsAndConditionsOptions = GMSNavigationTermsAndConditionsOptions(companyName: "Ride Sharing Co.")

  GMSNavigationServices.showTermsAndConditionsDialogIfNeeded(
    with: termsAndConditionsOptions) { termsAccepted in
    if termsAccepted {
      // Enable navigation if the user accepts the terms.
      self.mapView.isNavigationEnabled = true
      self.mapView.settings.compassButton = true

      // Request authorization to use location services.
      self.locationManager.requestAlwaysAuthorization()

      // Request authorization for alert notifications which deliver guidance instructions
      // in the background.
    UNUserNotificationCenter.current().requestAuthorization(options: [.alert]) {
      granted, error in
        // Handle rejection of notification authorization.
        if !granted || error != nil {
          print("Authorization to deliver notifications was rejected.")
        }
      }
    } else {
      // Handle rejection of terms and conditions.
    }
  }

GMSNavigationTermsAndConditionsOptions *termsAndConditionsOptions = [[GMSNavigationTermsAndConditionsOptions alloc] initWithCompanyName:@"Ride Sharing Co."];

[GMSNavigationServices
  showTermsAndConditionsDialogIfNeededWithOptions:termsAndConditionsOptions
  callback:^(BOOL termsAccepted) {
   if (termsAccepted) {
     // Enable navigation if the user accepts the terms.
     _mapView.navigationEnabled = YES;
     _mapView.settings.compassButton = YES;

     // Request authorization to use the current device location.
     [_locationManager requestAlwaysAuthorization];

     // Request authorization for alert notifications which deliver guidance instructions
     // in the background.
     UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
     UNAuthorizationOptions options = UNAuthorizationOptionAlert;
     [center requestAuthorizationWithOptions:options
                           completionHandler:
     ^(
       BOOL granted,
       NSError *_Nullable error) {
         if (!error && granted) {
           NSLog(@"iOS Notification Permission: newly Granted");
         } else {
           NSLog(@"iOS Notification Permission: Failed or Denied");
         }
       }];
   } else {
     // Handle rejection of the terms and conditions.
   }
 }];

Tạo tuyến đường và bắt đầu hướng dẫn

Để lập biểu đồ tuyến đường, hãy gọi phương thức setDestinations() của Trình điều hướng bằng một mảng chứa một hoặc nhiều đích đến (GMSNavigationWaypoint) cần truy cập. Nếu tính toán thành công, tuyến đường sẽ xuất hiện trên bản đồ. Để bắt đầu hướng dẫn dọc theo tuyến đường, bắt đầu từ đích đến đầu tiên, hãy đặt isGuidanceActive thành true trong lệnh gọi lại.

Ví dụ sau đây cho thấy:

  • Tạo một tuyến mới có hai đích đến.
  • Bắt đầu hướng dẫn.
  • Bật thông báo hướng dẫn ở chế độ nền.
  • Mô phỏng hành trình dọc theo tuyến đường (không bắt buộc).
  • Đặt chế độ máy ảnh thành "theo dõi" (không bắt buộc).

func startNav() {
  var destinations = [GMSNavigationWaypoint]()
  destinations.append(GMSNavigationWaypoint.init(placeID: "ChIJnUYTpNASkFQR_gSty5kyoUk",
                                                 title: "PCC Natural Market")!)
  destinations.append(GMSNavigationWaypoint.init(placeID:"ChIJJ326ROcSkFQRBfUzOL2DSbo",
                                                 title:"Marina Park")!)

  mapView.navigator?.setDestinations(destinations) { routeStatus in
    self.mapView.navigator?.isGuidanceActive = true
    self.mapView.locationSimulator?.simulateLocationsAlongExistingRoute()
    self.mapView.cameraMode = .following
  }
}

- (void)startNav {
  NSArray<GMSNavigationWaypoint *> *destinations =
  @[[[GMSNavigationWaypoint alloc] initWithPlaceID:@"ChIJnUYTpNASkFQR_gSty5kyoUk"
                                             title:@"PCC Natural Market"],
    [[GMSNavigationWaypoint alloc] initWithPlaceID:@"ChIJJ326ROcSkFQRBfUzOL2DSbo"
                                             title:@"Marina Park"]];

  [_mapView.navigator setDestinations:destinations
                             callback:^(GMSRouteStatus routeStatus){
                               [_mapView.locationSimulator simulateLocationsAlongExistingRoute];
                               _mapView.navigator.guidanceActive = YES;
                               _mapView.cameraMode = GMSNavigationCameraModeFollowing;
                             }];
}

Để tìm hiểu về Mã địa điểm, vui lòng tham khảo bài viết Mã địa điểm.

Đặt chế độ đi lại

Chế độ đi lại xác định loại tuyến đường sẽ được tìm nạp và cách xác định lộ trình của người dùng. Bạn có thể đặt một trong 4 phương thức di chuyển cho một tuyến đường: lái xe, đi xe đạp, đi bộ và đi taxi. Ở chế độ lái xe và taxi, lộ trình của người dùng dựa trên hướng di chuyển; ở chế độ đi xe đạp và đi bộ, lộ trình được biểu thị bằng hướng thiết bị đang hướng đến.

Đặt thuộc tính travelMode của thành phần hiển thị bản đồ, như trong ví dụ sau:

self.mapView.travelMode = .cycling

_mapView.travelMode = GMSNavigationTravelModeCycling;

Thiết lập đường cần tránh

Sử dụng thuộc tính BOOL avoidsHighwaysavoidsTolls để tránh đường cao tốc và/hoặc đường thu phí dọc theo tuyến đường.

self.mapView.navigator?.avoidsTolls = true

_mapView.navigator.avoidsTolls = YES;

Trình tìm PlaceID

Bạn có thể sử dụng Công cụ tìm mã địa điểm để tìm mã địa điểm dùng cho đích đến của tuyến đường. Thêm một đích đến từ placeID bằng GMSNavigationWaypoint.

Văn bản nổi

Bạn có thể thêm văn bản nổi ở bất kỳ đâu trong ứng dụng, miễn là không che khuất thông tin phân bổ của Google. SDK Điều hướng không hỗ trợ việc neo văn bản vào vĩ độ/kinh độ trên bản đồ hoặc vào nhãn. Để biết thêm thông tin, hãy xem phần Cửa sổ thông tin.