탐색 이벤트 리슨

이 가이드를 사용하여 앱이 사용자가 경로를 따라 이동할 때 변경되는 다양한 이벤트를 수신 대기하고 이에 응답하도록 설정하세요. 이 가이드에서는 경로 정의는 다루지 않고 경로의 이벤트에 응답하는 방법만 다룹니다.

개요

iOS용 Navigation SDK는 사용자 위치, 경로의 상태, 중요한 시간 및 거리 데이터와 연결된 리스너를 제공합니다. 지도의 뷰 컨트롤러에서 앱은 이러한 리스너의 프로토콜인 GMSRoadSnappedLocationProviderListenerGMSNavigatorListener를 채택해야 합니다.

다음 목록에는 탐색 이벤트에 사용할 수 있는 리스너 메서드가 나와 있습니다.

코드 보기

/*
 * Copyright 2020 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,
  GMSNavigatorListener,
  GMSRoadSnappedLocationProviderListener
{

  var mapView: GMSMapView!
  var locationManager: CLLocationManager!

  override func loadView() {

    locationManager = CLLocationManager()

    let camera = GMSCameraPosition.camera(withLatitude: 47.67, longitude: -122.20, zoom: 14)
    mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)

    // Add listeners for GMSNavigator and GMSRoadSnappedLocationProvider.
    mapView.navigator?.add(self)
    mapView.roadSnappedLocationProvider?.add(self)

    // Set the time update threshold (seconds) and distance update threshold (meters).
    mapView.navigator?.timeUpdateThreshold = 10
    mapView.navigator?.distanceUpdateThreshold = 100

    // 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

        // 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("Authorization to deliver notifications was rejected.")
          }
        }
      } else {
        // Handle the case when the user rejects the terms and conditions.
      }
    }

    view = mapView

    makeButton()
  }

  // Create a route and start guidance.
  @objc 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.cameraMode = .following
      self.mapView.locationSimulator?.simulateLocationsAlongExistingRoute()
    }

    mapView.roadSnappedLocationProvider?.startUpdatingLocation()
  }

  // Listener to handle continuous location updates.
  func locationProvider(
    _ locationProvider: GMSRoadSnappedLocationProvider,
    didUpdate location: CLLocation
  ) {
    print("Location: \(location.description)")
  }

  // Listener to handle speeding events.
  func navigator(
    _ navigator: GMSNavigator, didUpdateSpeedingPercentage percentageAboveLimit: CGFloat
  ) {
    print("Speed is \(percentageAboveLimit) above the limit.")
  }

  // Listener to handle arrival events.
  func navigator(_ navigator: GMSNavigator, didArriveAt waypoint: GMSNavigationWaypoint) {
    print("You have arrived at: \(waypoint.title)")
    mapView.navigator?.continueToNextDestination()
    mapView.navigator?.isGuidanceActive = true
  }

  // Listener for route change events.
  func navigatorDidChangeRoute(_ navigator: GMSNavigator) {
    print("The route has changed.")
  }

  // Listener for time to next destination.
  func navigator(_ navigator: GMSNavigator, didUpdateRemainingTime time: TimeInterval) {
    print("Time to next destination: \(time)")
  }

  // Delegate for distance to next destination.
  func navigator(
    _ navigator: GMSNavigator,
    didUpdateRemainingDistance distance: CLLocationDistance
  ) {
    let miles = distance * 0.00062137
    print("Distance to next destination: \(miles) miles.")
  }

  // Delegate for traffic updates to next destination
  func navigator(
    _ navigator: GMSNavigator,
    didUpdate delayCategory: GMSNavigationDelayCategory
  ) {
    print("Delay category to next destination: \(String(describing: delayCategory)).")
  }

  // Delegate for suggested lighting mode changes.
  func navigator(
    _ navigator: GMSNavigator,
    didChangeSuggestedLightingMode lightingMode: GMSNavigationLightingMode
  ) {
    print("Suggested lighting mode has changed: \(String(describing: lightingMode))")

    // Change to the suggested lighting mode.
    mapView.lightingMode = lightingMode
  }

  // Add a button to the view.
  func makeButton() {
    // 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 2020 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 () <GMSNavigatorListener, GMSRoadSnappedLocationProviderListener>

@end

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

- (void)loadView {

  _locationManager = [[CLLocationManager alloc] init];

  GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:47.67
                                                          longitude:-122.20
                                                               zoom:14];
  _mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];

  // Add listeners for GMSNavigator and GMSRoadSnappedLocationProvider.
  [_mapView.navigator addListener:self];
  [_mapView.roadSnappedLocationProvider addListener:self];

  // Set the time update threshold (seconds) and distance update threshold (meters).
  _mapView.navigator.timeUpdateThreshold = 10;
  _mapView.navigator.distanceUpdateThreshold = 100;

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

       // Request authorization to use location services.
       [_locationManager requestAlwaysAuthorization];

     } else {
       // Handle the case when the user rejects 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.navigator.guidanceActive = YES;
                               _mapView.navigator.sendsBackgroundNotifications = YES;
                               _mapView.cameraMode = GMSNavigationCameraModeFollowing;
                               [_mapView.locationSimulator simulateLocationsAlongExistingRoute];
                             }];

  [_mapView.roadSnappedLocationProvider startUpdatingLocation];
}

#pragma mark - GMSNavigatorListener
// Listener for continuous location updates.
- (void)locationProvider:(GMSRoadSnappedLocationProvider *)locationProvider
      didUpdateLocation:(CLLocation *)location {
  NSLog(@"Location: %@", location.description);
}

// Listener to handle speeding events.
- (void)navigator:(GMSNavigator *)navigator
    didUpdateSpeedingPercentage:(CGFloat)percentageAboveLimit {
  NSLog(@"Speed is %f percent above the limit.", percentageAboveLimit);
}

// Listener to handle arrival events.
- (void)navigator:(GMSNavigator *)navigator didArriveAtWaypoint:(GMSNavigationWaypoint *)waypoint {
  NSLog(@"You have arrived at: %@", waypoint.title);
  [_mapView.navigator continueToNextDestination];
  _mapView.navigator.guidanceActive = YES;
}

// Listener for route change events.
- (void)navigatorDidChangeRoute:(GMSNavigator *)navigator {
  NSLog(@"The route has changed.");
}

// Listener for time to next destination.
- (void)navigator:(GMSNavigator *)navigator didUpdateRemainingTime:(NSTimeInterval)time {
  NSLog(@"Time to next destination: %f", time);
}

// Listener for distance to next destination.
- (void)navigator:(GMSNavigator *)navigator
      didUpdateRemainingDistance:(CLLocationDistance)distance {
  double miles = distance * 0.00062137;
  NSLog(@"%@", [NSString stringWithFormat:@"Distance to next destination: %.2f.", miles]);
}

// Listener for traffic updates for next destination
- (void)navigator:(GMSNavigator *)navigator
    didUpdateDelayCategory:(GMSNavigationDelayCategory)delayCategory {
  NSLog(@"Delay category to next destination: %ld.", delayCategory);
}

// Listener for suggested lighting mode changes.
-(void)navigator:(GMSNavigator *)navigator
      didChangeSuggestedLightingMode:(GMSNavigationLightingMode)lightingMode {
  NSLog(@"Suggested lighting mode has changed: %ld", (long)lightingMode);

  // Change to the suggested lighting mode.
  _mapView.lightingMode = lightingMode;
}

#pragma mark - Programmatic UI elements

// Add a button to the view.
- (void)makeButton {
  // 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 setAlpha:0.5];
  navButton.frame = CGRectMake(5.0, 150.0, 100.0, 35.0);
  [_mapView addSubview:navButton];
}

@end

필수 프로토콜 준수 선언

뷰 컨트롤러는 탐색 메서드를 구현하기 전에 다음 프로토콜을 채택해야 합니다.

SwiftObjective-C

class ViewController: UIViewController, GMSNavigatorListener,
GMSRoadSnappedLocationProviderListener {

@interface ViewController () <GMSNavigatorListener,
GMSRoadSnappedLocationProviderListener>

@end

탐색 프로토콜을 채택한 후 리스너를 뷰 컨트롤러로 설정합니다. 예를 들어 viewDidLoad() 메서드에 다음 코드를 추가할 수 있습니다.

SwiftObjective-C

mapView.navigator?.add(self) mapView.roadSnappedLocationProvider?.add(self)

[_mapView.navigator addListener:self]; [_mapView.roadSnappedLocationProvider
addListener:self];

위치 업데이트 수신 또는 중지

지도에 사용자의 진행 상황을 표시하려면 위치 업데이트가 필요합니다.

location 인스턴스는 다음 속성을 노출합니다.

위치 속성 설명
고도 현재 고도입니다.
coordinate.latitude 현재 도로 스냅 위도 좌표입니다.
coordinate.longitude 현재 도로 스냅 경도 좌표입니다.
강의 현재 방향(도)입니다.
속도 현재 속도입니다.
타임스탬프 현재 판독값의 날짜/시간입니다.

연속적인 위치 업데이트를 수신하려면 mapView.roadSnappedLocationProvider.startUpdatingLocation를 호출하고 GMSRoadSnappedLocationProviderListener를 사용하여 didUpdateLocation 이벤트를 처리합니다.

다음은 startUpdatingLocation를 호출하는 예를 보여줍니다.

SwiftObjective-C

mapView.roadSnappedLocationProvider.startUpdatingLocation()

[_mapView.roadSnappedLocationProvider startUpdatingLocation];

다음 코드는 didUpdateLocation 이벤트를 처리하는 GMSRoadSnappedLocationProviderListener를 만듭니다.

SwiftObjective-C

func locationProvider(_ locationProvider: GMSRoadSnappedLocationProvider,
didUpdate location: CLLocation) { print("Location: \(location.description)") }

-   (void)locationProvider:(GMSRoadSnappedLocationProvider *)locationProvider
    didUpdateLocation:(CLLocation *)location { NSLog(@"Location: %@",
    location.description); }

앱이 백그라운드에 있을 때 위치 업데이트를 수신하려면 allowsBackgroundLocationUpdates를 true로 설정하세요.

SwiftObjective-C

mapView.roadSnappedLocationProvider.allowsBackgroundLocationUpdates = true

 _mapView.roadSnappedLocationProvider.allowsBackgroundLocationUpdates = YES;

도착 이벤트 감지

앱은 didArriveAtWaypoint 이벤트를 사용하여 대상에 도달했음을 감지합니다. continueToNextDestination()를 호출한 다음 안내를 다시 사용 설정하여 안내를 재개하고 다음 중간 지점으로 이동할 수 있습니다. 앱은 continueToNextDestination()를 호출한 후에 안내를 다시 사용 설정해야 합니다.

앱이 continueToNextDestination를 호출하면 더 이상 이전 대상에 관한 데이터가 내비게이터에 없습니다. 경로 구간에 관한 정보를 분석하려면 continueToNextDestination()를 호출하기 전에 탐색기에서 이를 가져와야 합니다.

다음 코드 예는 didArriveAtWaypoint 이벤트를 처리하는 메서드를 보여줍니다.

SwiftObjective-C

func navigator(_ navigator: GMSNavigator, didArriveAt waypoint:
GMSNavigationWaypoint) { print("You have arrived at: \(waypoint.title)")
mapView.navigator?.continueToNextDestination()
mapView.navigator?.isGuidanceActive = true }

-   (void)navigator:(GMSNavigator *)navigator
    didArriveAtWaypoint:(GMSNavigationWaypoint *)waypoint { NSLog(@"You have
    arrived at: %@", waypoint.title); [_mapView.navigator
    continueToNextDestination]; _mapView.navigator.guidanceActive = YES; }

경로 변경 업데이트 수신

경로가 변경될 때마다 알림을 받으려면 navigatorDidChangeRoute 이벤트를 처리하는 메서드를 만듭니다. GMSNavigatorrouteLegscurrentRouteLeg 속성을 사용하여 새 경로에 액세스할 수 있습니다.

SwiftObjective-C

func navigatorDidChangeRoute(_ navigator: GMSNavigator) { print("The route has
changed.") }

-   (void)navigatorDidChangeRoute:(GMSNavigator *)navigator { NSLog(@"The route
    has changed."); }

도착까지의 예상 시간 업데이트 수신

목적지까지의 시간 업데이트를 연속으로 수신하려면 didUpdateRemainingTime 이벤트를 처리하는 메서드를 만듭니다. time 매개변수는 다음 대상에 도달할 때까지의 예상 시간을 초 단위로 제공합니다.

SwiftObjective-C

func navigator(_ navigator: GMSNavigator, didUpdateRemainingTime time:
TimeInterval) { print("Time to next destination: \(time)") }

-   (void)navigator:(GMSNavigator *)navigator
    didUpdateRemainingTime:(NSTimeInterval)time { NSLog(@"Time to next
    destination: %f", time); }

다음 도착지에 도착하는 데 걸리는 예상 시간의 최소 변경 값을 설정하려면 GMSNavigator에서 timeUpdateThreshold 속성을 설정하세요. 값은 초 단위로 지정됩니다. 이 속성을 설정하지 않으면 서비스는 기본값인 1초를 사용합니다.

SwiftObjective-C

navigator?.timeUpdateThreshold = 10

navigator.timeUpdateThreshold = 10;

목적지까지의 거리 업데이트 수신

목적지까지의 거리 업데이트를 지속적으로 수신하려면 didUpdateRemainingDistance 이벤트를 처리하는 메서드를 만듭니다. distance 매개변수는 다음 목적지까지의 예상 거리(단위: 미터)를 제공합니다.

SwiftObjective-C

func navigator(_ navigator: GMSNavigator, didUpdateRemainingDistance distance:
CLLocationDistance) { let miles = distance * 0.00062137 print("Distance to next
destination: \(miles) miles.") }

-   (void)navigator:(GMSNavigator *)navigator
    didUpdateRemainingDistance:(CLLocationDistance)distance { double miles =
    distance * 0.00062137; NSLog(@"%@", [NSString stringWithFormat:@"Distance to
    next destination: %.2f.", miles]); }

다음 도착지에 대한 예상 거리의 최소 변경사항을 설정하려면 GMSNavigator에서 distanceUpdateThreshold 속성을 설정합니다 (값은 미터로 지정됨). 이 속성을 설정하지 않으면 서비스는 기본값인 1미터를 사용합니다.

SwiftObjective-C

navigator?.distanceUpdateThreshold = 100

navigator.distanceUpdateThreshold = 100;

교통정보 업데이트 받기

나머지 경로의 교통 흐름에 대한 지속적인 업데이트를 수신하려면 didUpdateDelayCategory 이벤트를 처리하는 메서드를 만듭니다. delayCategoryToNextDestination 호출은 0~3의 값을 제공하는 GMSNavigationDelayCategory를 반환합니다. 카테고리 업데이트는 앱 사용자의 현재 위치를 기반으로 합니다. 트래픽 데이터를 사용할 수 없는 경우 GMSNavigationDelayCategory는 0을 반환합니다. 숫자 1~3은 흐름이 약에서 강으로 증가함을 나타냅니다.

SwiftObjective-C

func navigator(_ navigator: GMSNavigator, didUpdate delayCategory:
GMSNavigationDelayCategory) { print("Traffic flow to next destination:
\(delayCategory)") }

-   (void)navigator:(GMSNavigator *)navigator
    didUpdateDelayCategory:(GMSNavigationDelayCategory)delayCategory {
    NSLog(@"Traffic flow to next destination: %ld", (long)delayCategory); }

GMSNavigationDelayCategory 속성은 다음과 같은 지연 수준을 노출합니다.

지연 카테고리 설명
GMSNavigationDelayCategoryNoData 0 - 사용 불가, 트래픽 데이터 없음 또는 :
경로를 확인할 수 있습니다.
GMSNavigationDelayCategoryHeavy 1 - 심함
GMSNavigationDelayCategoryMedium 2 - 중간
GMSNavigationDelayCategoryLight 3 - 밝음

속도 위반 업데이트 수신

운전자가 속도 제한을 초과할 때 업데이트를 수신하려면 didUpdateSpeedingPercentage 이벤트를 처리하는 메서드를 만듭니다.

SwiftObjective-C

// Listener to handle speeding events. func navigator( _ navigator:
GMSNavigator, didUpdateSpeedingPercentage percentageAboveLimit: CGFloat ) {
print("Speed is \(percentageAboveLimit) above the limit.") }

// Listener to handle speeding events. - (void)navigator:(GMSNavigator
*)navigator didUpdateSpeedingPercentage:(CGFloat)percentageAboveLimit {
NSLog(@"Speed is %f percent above the limit.", percentageAboveLimit); }

추천 조명 모드 변경하기

예상되는 조명 변경사항에 관한 업데이트를 수신하려면 didChangeSuggestedLightingMode 이벤트를 처리하는 메서드를 만듭니다.

SwiftObjective-C

// Define a listener for suggested changes to lighting mode. func navigator(_
navigator: GMSNavigator, didChangeSuggestedLightingMode lightingMode:
GMSNavigationLightingMode) { print("Suggested lighting mode has changed:
\(String(describing: lightingMode))")

 // Make the suggested change. mapView.lightingMode = lightingMode }

// Define a listener for suggested changes to lighting mode.
-(void)navigator:(GMSNavigator *)navigator didChangeSuggestedLightingMode:
(GMSNavigationLightingMode)lightingMode { NSLog(@"Suggested lighting mode has
changed: %ld", (long)lightingMode);

 // Make the suggested change. _mapView.lightingMode = lightingMode; }