Use this guide to enable your app to listen and respond to a variety of events
that change as a user navigates along a route. This guide does not cover
defining a route, only responding to events along a route.
Overview
The Navigation SDK for iOS provides you with listeners
associated with the location of the user and conditions along the route and
important time and distance data. On the view controller of the map, your app
needs to adopt the protocols for these listeners:
GMSRoadSnappedLocationProviderListener
and
GMSNavigatorListener.
This list shows the listener methods available for navigation events:
/**Copyright2020GoogleInc.Allrightsreserved.**LicensedundertheApacheLicense,Version2.0(the"License");*youmaynotusethisfileexceptincompliancewiththeLicense.*YoumayobtainacopyoftheLicenseat**http://www.apache.org/licenses/LICENSE-2.0**Unlessrequiredbyapplicablelaworagreedtoinwriting,software*distributedundertheLicenseisdistributedonan"AS IS"BASIS,*WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.*SeetheLicenseforthespecificlanguagegoverningpermissionsand*limitationsundertheLicense.*/importGoogleNavigationimportUIKitclassViewController:UIViewController,GMSNavigatorListener,GMSRoadSnappedLocationProviderListener{varmapView:GMSMapView!varlocationManager:CLLocationManager!overridefuncloadView(){locationManager=CLLocationManager()letcamera=GMSCameraPosition.camera(withLatitude:47.67,longitude:-122.20,zoom:14)mapView=GMSMapView.map(withFrame:CGRect.zero,camera:camera)//AddlistenersforGMSNavigatorandGMSRoadSnappedLocationProvider.mapView.navigator?.add(self)mapView.roadSnappedLocationProvider?.add(self)//Setthetimeupdatethreshold(seconds)anddistanceupdatethreshold(meters).mapView.navigator?.timeUpdateThreshold=10mapView.navigator?.distanceUpdateThreshold=100//Showthetermsandconditions.letcompanyName="Ride Sharing Co."GMSNavigationServices.showTermsAndConditionsDialogIfNeeded(withCompanyName:companyName){termsAcceptediniftermsAccepted{//Enablenavigationiftheuseracceptstheterms.self.mapView.isNavigationEnabled=true//Requestauthorizationtouselocationservices.self.locationManager.requestAlwaysAuthorization()//Requestauthorizationforalertnotificationswhichdeliverguidanceinstructions//inthebackground.UNUserNotificationCenter.current().requestAuthorization(options:[.alert]){granted,errorin//Handledeniedauthorizationtodisplaynotifications.if!granted||error!=nil{print("Authorization to deliver notifications was rejected.")}}}else{//Handlethecasewhentheuserrejectsthetermsandconditions.}}view=mapViewmakeButton()}//Createarouteandstartguidance.@objcfuncstartNav(){vardestinations=[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){routeStatusinguardrouteStatus==.OKelse{print("Handle route statuses that are not OK.")return}self.mapView.navigator?.isGuidanceActive=trueself.mapView.cameraMode=.followingself.mapView.locationSimulator?.simulateLocationsAlongExistingRoute()}mapView.roadSnappedLocationProvider?.startUpdatingLocation()}//Listenertohandlecontinuouslocationupdates.funclocationProvider(_locationProvider:GMSRoadSnappedLocationProvider,didUpdatelocation:CLLocation){print("Location: \(location.description)")}//Listenertohandlespeedingevents.funcnavigator(_navigator:GMSNavigator,didUpdateSpeedingPercentagepercentageAboveLimit:CGFloat){print("Speed is \(percentageAboveLimit) above the limit.")}//Listenertohandlearrivalevents.funcnavigator(_navigator:GMSNavigator,didArriveAtwaypoint:GMSNavigationWaypoint){print("You have arrived at: \(waypoint.title)")mapView.navigator?.continueToNextDestination()mapView.navigator?.isGuidanceActive=true}//Listenerforroutechangeevents.funcnavigatorDidChangeRoute(_navigator:GMSNavigator){print("The route has changed.")}//Listenerfortimetonextdestination.funcnavigator(_navigator:GMSNavigator,didUpdateRemainingTimetime:TimeInterval){print("Time to next destination: \(time)")}//Delegatefordistancetonextdestination.funcnavigator(_navigator:GMSNavigator,didUpdateRemainingDistancedistance:CLLocationDistance){letmiles=distance*0.00062137print("Distance to next destination: \(miles) miles.")}//Delegatefortrafficupdatestonextdestinationfuncnavigator(_navigator:GMSNavigator,didUpdatedelayCategory:GMSNavigationDelayCategory){print("Delay category to next destination: \(String(describing: delayCategory)).")}//Delegateforsuggestedlightingmodechanges.funcnavigator(_navigator:GMSNavigator,didChangeSuggestedLightingModelightingMode:GMSNavigationLightingMode){print("Suggested lighting mode has changed: \(String(describing: lightingMode))")//Changetothesuggestedlightingmode.mapView.lightingMode=lightingMode}//Addabuttontotheview.funcmakeButton(){//Startnavigation.letnavButton=UIButton(frame:CGRect(x:5,y:150,width:200,height:35))navButton.backgroundColor=.bluenavButton.alpha=0.5navButton.setTitle("Start navigation",for:.normal)navButton.addTarget(self,action:#selector(startNav), for: .touchUpInside)self.mapView.addSubview(navButton)}}
Show/Hide the Objective-C code for an 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"@importGoogleNavigation;@interfaceViewController()<GMSNavigatorListener,GMSRoadSnappedLocationProviderListener>
@end@implementationViewController{GMSMapView*_mapView;CLLocationManager*_locationManager;}-(void)loadView{_locationManager=[[CLLocationManageralloc]init];GMSCameraPosition*camera=[GMSCameraPositioncameraWithLatitude:47.67longitude:-122.20zoom:14];_mapView=[GMSMapViewmapWithFrame:CGRectZerocamera:camera];// Add listeners for GMSNavigator and GMSRoadSnappedLocationProvider.[_mapView.navigatoraddListener:self];[_mapView.roadSnappedLocationProvideraddListener: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.";[GMSNavigationServicesshowTermsAndConditionsDialogIfNeededWithCompanyName:companyNamecallback:^(BOOLtermsAccepted){if(termsAccepted){// Enable navigation if the user accepts the terms._mapView.navigationEnabled=YES;// Request authorization to use location services.[_locationManagerrequestAlwaysAuthorization];}else{// Handle the case when the user rejects the terms and conditions.}}];self.view=_mapView;[selfmakeButton];}// Create a route and initiate navigation.-(void)startNav{NSArray<GMSNavigationWaypoint*>*destinations=@[[[GMSNavigationWaypointalloc]initWithPlaceID:@"ChIJnUYTpNASkFQR_gSty5kyoUk"title:@"PCC Natural Market"],[[GMSNavigationWaypointalloc]initWithPlaceID:@"ChIJJ326ROcSkFQRBfUzOL2DSbo"title:@"Marina Park"]];[_mapView.navigatorsetDestinations:destinationscallback:^(GMSRouteStatusrouteStatus){_mapView.navigator.guidanceActive=YES;_mapView.navigator.sendsBackgroundNotifications=YES;_mapView.cameraMode=GMSNavigationCameraModeFollowing;[_mapView.locationSimulatorsimulateLocationsAlongExistingRoute];}];[_mapView.roadSnappedLocationProviderstartUpdatingLocation];}#pragma mark - GMSNavigatorListener// Listener for continuous location updates.-(void)locationProvider:(GMSRoadSnappedLocationProvider*)locationProviderdidUpdateLocation:(CLLocation*)location{NSLog(@"Location: %@",location.description);}// Listener to handle speeding events.-(void)navigator:(GMSNavigator*)navigatordidUpdateSpeedingPercentage:(CGFloat)percentageAboveLimit{NSLog(@"Speed is %f percent above the limit.",percentageAboveLimit);}// Listener to handle arrival events.-(void)navigator:(GMSNavigator*)navigatordidArriveAtWaypoint:(GMSNavigationWaypoint*)waypoint{NSLog(@"You have arrived at: %@",waypoint.title);[_mapView.navigatorcontinueToNextDestination];_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*)navigatordidUpdateRemainingTime:(NSTimeInterval)time{NSLog(@"Time to next destination: %f",time);}// Listener for distance to next destination.-(void)navigator:(GMSNavigator*)navigatordidUpdateRemainingDistance:(CLLocationDistance)distance{doublemiles=distance*0.00062137;NSLog(@"%@",[NSStringstringWithFormat:@"Distance to next destination: %.2f.",miles]);}// Listener for traffic updates for next destination-(void)navigator:(GMSNavigator*)navigatordidUpdateDelayCategory:(GMSNavigationDelayCategory)delayCategory{NSLog(@"Delay category to next destination: %ld.",delayCategory);}// Listener for suggested lighting mode changes.-(void)navigator:(GMSNavigator*)navigatordidChangeSuggestedLightingMode:(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=[UIButtonbuttonWithType:UIButtonTypeCustom];[navButtonaddTarget:selfaction:@selector(startNav)forControlEvents:UIControlEventTouchUpInside];[navButtonsetTitle:@"Navigate"forState:UIControlStateNormal];[navButtonsetBackgroundColor:[UIColorblueColor]];[navButtonsetAlpha:0.5];navButton.frame=CGRectMake(5.0,150.0,100.0,35.0);[_mapViewaddSubview:navButton];}@end
Declaring conformance to the required protocols
Before implementing the navigation methods, the view controller must adopt the
protocols:
After adopting the navigation protocols, set the listeners to the view
controller. For example, you can add the following code to the viewDidLoad()
method.
Location updates are required for showing the user's progress on the map.
The location instance exposes the following properties:
Location property
Description
altitude
Current altitude.
coordinate.latitude
Current road-snapped latitude coordinate.
coordinate.longitude
Current road-snapped longitude coordinate.
course
Current bearing in degrees.
speed
Current speed.
timestamp
Date/time of current reading.
To receive continuous location updates, call
mapView.roadSnappedLocationProvider.startUpdatingLocation , and use the
GMSRoadSnappedLocationProviderListener to handle the didUpdateLocation
event.
The following example shows calling startUpdatingLocation:
Your app uses the didArriveAtWaypoint event to detect when a destination has
been reached. You can resume guidance and advance to the next waypoint by
calling continueToNextDestination(), and then re-enabling guidance. Your app
must re-enable guidance after calling continueToNextDestination().
After the app calls continueToNextDestination, the navigator no longer has
data about the previous destination. If you want to analyze information about a
route leg, you must retrieve this from the navigator prior to calling
continueToNextDestination().
The following code example shows a method to handle the didArriveAtWaypoint
event:
Swift
funcnavigator(_navigator:GMSNavigator,didArriveAtwaypoint:GMSNavigationWaypoint){print("You have arrived at: \(waypoint.title)")mapView.navigator?.continueToNextDestination()mapView.navigator?.isGuidanceActive=true}
To receive a notification whenever the route is changed, create a method to
handle the navigatorDidChangeRoute event. You can access the new route by
using the routeLegs and currentRouteLeg properties of GMSNavigator.
To receive continuous time to destination updates, create a method to handle the
didUpdateRemainingTime event. The time parameter provides the estimated
time, in seconds, until the next destination is reached.
Swift
funcnavigator(_navigator:GMSNavigator,didUpdateRemainingTimetime:TimeInterval){print("Time to next destination: \(time)")}
Objective-C
-(void)navigator:(GMSNavigator*)navigatordidUpdateRemainingTime:(NSTimeInterval)time{NSLog(@"Time to nextdestination:%f", time); }
To set the minimum change in estimated time to the next destination, set the
timeUpdateThreshold property on GMSNavigator. The value is specified in
seconds. If this property is not set, the services use a default value of one
second.
Swift
navigator?.timeUpdateThreshold=10
Objective-C
navigator.timeUpdateThreshold=10;
Receiving distance to destination updates
To receive continuous distance to destination updates, create a method to handle
the didUpdateRemainingDistance event. The distance parameter provides the
estimated distance, in meters, to the next destination.
Swift
funcnavigator(_navigator:GMSNavigator,didUpdateRemainingDistancedistance:CLLocationDistance){letmiles=distance*0.00062137print("Distance to nextdestination: \(miles) miles.")}
To set the minimum change in estimated distance to the next destination, set the
distanceUpdateThreshold property on GMSNavigator (value is specified in
meters). If this property is not set, the services use a default value of one
meter.
Swift
navigator?.distanceUpdateThreshold=100
Objective-C
navigator.distanceUpdateThreshold=100;
Receiving traffic updates
To receive continuous updates of the traffic flow for the remaining route,
create a method to handle the didUpdateDelayCategory event. A call to
delayCategoryToNextDestination returns GMSNavigationDelayCategory which
provides a value of 0 to 3. Updates to the category are based on the current
position of the app user. If traffic data is unavailable,
GMSNavigationDelayCategory returns 0. The numbers, 1-3, indicate increasing
flow from light to heavy.
Swift
funcnavigator(_navigator:GMSNavigator,didUpdatedelayCategory:GMSNavigationDelayCategory){print("Traffic flow to next destination:\(delayCategory)")}
Objective-C
-(void)navigator:(GMSNavigator*)navigatordidUpdateDelayCategory:(GMSNavigationDelayCategory)delayCategory{NSLog(@"Traffic flow to next destination: %ld",(long)delayCategory);}
The GMSNavigationDelayCategory property exposes the following delay levels:
Delay category
Description
GMSNavigationDelayCategoryNoData
0 - Unavailable, no data for traffic or :
the route.
GMSNavigationDelayCategoryHeavy
1 - Heavy.
GMSNavigationDelayCategoryMedium
2 - Medium.
GMSNavigationDelayCategoryLight
3 - Light.
Receiving speeding updates
To receive updates when a driver is exceeding the speed limit, create a method
to handle the didUpdateSpeedingPercentage event.
Swift
// Listener to handle speeding events. func navigator( _ navigator:GMSNavigator,didUpdateSpeedingPercentagepercentageAboveLimit:CGFloat){print("Speed is \(percentageAboveLimit) above the limit.")}
Objective-C
// Listener to handle speeding events. - (void)navigator:(GMSNavigator*)navigatordidUpdateSpeedingPercentage:(CGFloat)percentageAboveLimit{NSLog(@"Speed is %f percent above the limit.",percentageAboveLimit);}
Changing suggested lighting mode
To receive updates for estimated changes in lighting, create a method to handle
the didChangeSuggestedLightingMode event.
Swift
// Define a listener for suggested changes to lighting mode. func navigator(_navigator:GMSNavigator,didChangeSuggestedLightingModelightingMode:GMSNavigationLightingMode){print("Suggested lighting mode has changed:\(String(describing:lightingMode))")// Make the suggested change. mapView.lightingMode = lightingMode }
Objective-C
// Define a listener for suggested changes to lighting mode.-(void)navigator:(GMSNavigator*)navigatordidChangeSuggestedLightingMode:(GMSNavigationLightingMode)lightingMode{NSLog(@"Suggested lighting mode haschanged:%ld", (long)lightingMode);// Make the suggested change. _mapView.lightingMode = lightingMode; }