通过本指南,您可以让应用监听并响应随着用户沿着路线导航而发生变化的各种事件。本指南不介绍如何定义路线,只介绍如何响应路线上的事件。
概览
Navigation SDK for iOS 可为您提供与用户位置和路线沿途情况相关联的监听器,以及重要的时间和距离数据。在地图的视图控制器上,您的应用需要采用以下监听器的协议:GMSRoadSnappedLocationProviderListener
和 GMSNavigatorListener
。
以下列表显示了可用于导航事件的监听器方法:
GMSNavigatorListener.didArriveAtWaypoint
,在到达目的地时触发。GMSNavigatorListener.navigatorDidChangeRoute
:当路线发生变化时触发。GMSNavigatorListener.didUpdateRemainingTime
,在导航处于活动状态时,随着到达下一个目的地的时间而重复调用。GMSNavigatorListener.didUpdateRemainingDistance
:在导航处于活动状态时,当距离下一个目的地的距离发生变化时,会重复调用此方法。GMSNavigatorListener.didUpdateDelayCategory
:在导航处于活动状态时,当到下一个目的地的延迟类别发生变化时调用。GMSNavigatorListener.didChangeSuggestedLightingMode
:当估算的光照条件更新时触发。例如,当用户当前所在地进入夜晚时,光线会发生变化。GMSNavigatorListener.didUpdateSpeedingPercentage
:当驾驶员超速时触发。GMSRoadSnappedLocationProviderListener.didUpdateLocation
,在用户的位置发生变化时重复调用。
查看代码
显示/隐藏事件监听器的 Swift 代码。
/* * 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) } }
显示/隐藏事件监听器的 Objective-C 代码。
/* * 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
声明符合所需协议
在实现导航方法之前,视图控制器必须采用以下协议:
class ViewController: UIViewController, GMSNavigatorListener,
GMSRoadSnappedLocationProviderListener {
@interface ViewController () <GMSNavigatorListener,
GMSRoadSnappedLocationProviderListener>
@end
采用导航协议后,将监听器设置为视图控制器。例如,您可以将以下代码添加到 viewDidLoad()
方法中。
mapView.navigator?.add(self) mapView.roadSnappedLocationProvider?.add(self)
[_mapView.navigator addListener:self]; [_mapView.roadSnappedLocationProvider
addListener:self];
接收或停止接收位置信息更新
如需在地图上显示用户的进度,必须进行位置更新。
location
实例公开了以下属性:
地点属性 | 说明 |
---|---|
altitude | 当前海拔。 |
coordinate.latitude | 当前的道路贴靠纬度坐标。 |
coordinate.longitude | 当前的道路贴靠经度坐标。 |
课程 | 当前航向(以度为单位)。 |
速度 | 当前速度。 |
时间戳 | 当前读数的日期/时间。 |
如需接收持续位置信息更新,请调用 mapView.roadSnappedLocationProvider.startUpdatingLocation
,并使用 GMSRoadSnappedLocationProviderListener
处理 didUpdateLocation
事件。
以下示例展示了如何调用 startUpdatingLocation
:
mapView.roadSnappedLocationProvider.startUpdatingLocation()
[_mapView.roadSnappedLocationProvider startUpdatingLocation];
以下代码会创建一个用于处理 didUpdateLocation
事件的 GMSRoadSnappedLocationProviderListener
。
func locationProvider(_ locationProvider: GMSRoadSnappedLocationProvider,
didUpdate location: CLLocation) { print("Location: \(location.description)") }
- (void)locationProvider:(GMSRoadSnappedLocationProvider *)locationProvider
didUpdateLocation:(CLLocation *)location { NSLog(@"Location: %@",
location.description); }
如需在应用在后台运行时接收位置信息更新,请将 allowsBackgroundLocationUpdates
设置为 true:
mapView.roadSnappedLocationProvider.allowsBackgroundLocationUpdates = true
_mapView.roadSnappedLocationProvider.allowsBackgroundLocationUpdates = YES;
检测到达事件
您的应用使用 didArriveAtWaypoint
事件检测何时到达目的地。您可以调用 continueToNextDestination()
,然后重新启用导航,以恢复导航并前往下一个航点。您的应用必须在调用 continueToNextDestination()
后重新启用引导。
应用调用 continueToNextDestination
后,导航器将不再拥有与上一个目的地相关的数据。如果您想分析路线航段的相关信息,则必须先从导航器中检索这些信息,然后再调用 continueToNextDestination()
。
以下代码示例展示了处理 didArriveAtWaypoint
事件的方法:
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
事件的方法。您可以使用 GMSNavigator
的 routeLegs
和 currentRouteLeg
属性访问新路线。
func navigatorDidChangeRoute(_ navigator: GMSNavigator) { print("The route has
changed.") }
- (void)navigatorDidChangeRoute:(GMSNavigator *)navigator { NSLog(@"The route
has changed."); }
接收目的地到达时间更新
如需接收持续更新的目的地到达时间,请创建一个用于处理 didUpdateRemainingTime
事件的方法。time
参数提供到达下一个目的地所需的预计时间(以秒为单位)。
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 秒。
navigator?.timeUpdateThreshold = 10
navigator.timeUpdateThreshold = 10;
接收到达目的地的距离更新
如需接收持续更新的距离目的地信息,请创建一个用于处理 didUpdateRemainingDistance
事件的方法。distance
参数提供到下一个目的地的预计距离(以米为单位)。
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 米。
navigator?.distanceUpdateThreshold = 100
navigator.distanceUpdateThreshold = 100;
接收路况动态
如需接收剩余路线的交通流量持续更新,请创建一个用于处理 didUpdateDelayCategory
事件的方法。调用 delayCategoryToNextDestination
会返回 GMSNavigationDelayCategory
,该值的范围为 0 到 3。对此类别的更新基于应用用户的当前位置。如果没有可用流量数据,GMSNavigationDelayCategory
会返回 0。数字 1-3 表示流量从小到大。
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
事件的方法。
// 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
事件的方法。
// 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; }