您可以參考本指南,讓應用程式監聽並回應使用者沿著路線前進時發生的各種事件變化。本指南不會說明如何定義路線,只會說明如何回應沿路的事件。
總覽
iOS 版 Navigation SDK 會提供與使用者位置和路線沿途狀況相關的事件監聽器,以及重要時間和距離資料。在地圖的 View Controller 中,應用程式需要採用下列事件監聽器的通訊協定: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
宣告符合必要通訊協定
在實作導覽方法之前,View Controller 必須採用下列通訊協定:
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
例項會公開下列屬性:
位置屬性 | 說明 |
---|---|
高度 | 目前的高度。 |
coordinate.latitude | 目前經過道路對齊的緯度座標。 |
coordinate.longitude | 目前經過路徑修正的經度座標。 |
課程 | 目前航向 (以度為單位)。 |
速度 | 目前速度。 |
時間戳記 | 目前讀數的日期/時間。 |
如要接收持續的位置更新,請呼叫 mapView.roadSnappedLocationProvider.startUpdatingLocation
,並使用 GMSRoadSnappedLocationProviderListener
處理 didUpdateLocation
事件。
下例示範如何呼叫 startUpdatingLocation
:
mapView.roadSnappedLocationProvider.startUpdatingLocation()
[_mapView.roadSnappedLocationProvider startUpdatingLocation];
以下程式碼會建立 GMSRoadSnappedLocationProviderListener
,用於處理 didUpdateLocation
事件。
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
屬性。這個值以秒為單位。如果未設定此屬性,服務會使用一秒的預設值。
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
屬性 (值以公尺為單位)。如果未設定這個屬性,服務會使用一公尺的預設值。
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; }