במדריך הזה מוסבר איך לאפשר לאפליקציה להאזין לאירועים שונים ולענות להם, אירועים שמשתנים כשהמשתמש מנווט במסלול. המדריך הזה לא עוסק בהגדרת מסלול, אלא רק בתגובה לאירועים במסלול.
סקירה כללית
Navigation SDK ל-iOS מספק מאזינים שמשויכים למיקום המשתמש ולתנאים לאורך המסלול, ונתונים חשובים לגבי זמן ומרחק. ב-view controller של המפה, האפליקציה צריכה לאמץ את הפרוטוקולים של המאזינים האלה: GMSRoadSnappedLocationProviderListener
ו-GMSNavigatorListener
.
ברשימה הזו מפורטות שיטות המאזין הזמינות לאירועי ניווט:
GMSNavigatorListener.didArriveAtWaypoint
, שמופעל כשמגיעים ליעד.GMSNavigatorListener.navigatorDidChangeRoute
, שמופעל כשהמסלול משתנה.GMSNavigatorListener.didUpdateRemainingTime
, שנקרא שוב ושוב כשהזמן ליעד הבא משתנה, בזמן שההנחיה פעילה.GMSNavigatorListener.didUpdateRemainingDistance
, שנקרא שוב ושוב כשהמרחק ליעד הבא משתנה, בזמן שההנחיה פעילה.GMSNavigatorListener.didUpdateDelayCategory
, שנקרא כשקטגוריית העיכוב ליעד הבא משתנה, בזמן שההנחיה פעילה.GMSNavigatorListener.didChangeSuggestedLightingMode
, שמופעל כשתנאי התאורה המשוערים מתעדכנים. לדוגמה, כשהלילה יורד במיקום הנוכחי של המשתמש, התאורה משתנה.GMSNavigatorListener.didUpdateSpeedingPercentage
, שמופעל כשהנהג חורג ממגבלת המהירות.GMSRoadSnappedLocationProviderListener.didUpdateLocation
, שנקרא שוב ושוב כשהמיקום של המשתמש משתנה.
הצגת הקוד
הצגה/הסתרה של הקוד ב-Swift של פונקציית ה-event listener.
/* * 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 של פונקציית event listener.
/* * 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
אחרי שמאמצים את פרוטוקולי הניווט, מגדירים את המאזינים ל-View Controller. לדוגמה, אפשר להוסיף את הקוד הבא לשיטה 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
. אפשר לגשת למסלול החדש באמצעות המאפיינים routeLegs
ו-currentRouteLeg
של GMSNavigator
.
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); }
כדי להגדיר את השינוי המינימלי בזמן המשוער ליעד הבא, מגדירים את המאפיין timeUpdateThreshold
כ-GMSNavigator
. הערך מצוין בשניות. אם לא מגדירים את המאפיין הזה, השירותים משתמשים בערך ברירת המחדל של שנייה אחת.
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]); }
כדי להגדיר את השינוי המינימלי במרחק המשוער ליעד הבא, מגדירים את המאפיין distanceUpdateThreshold
לערך GMSNavigator
(הערך מצוין במטרים). אם לא מגדירים את המאפיין הזה, השירותים משתמשים בערך ברירת המחדל של מטר אחד.
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; }