SDK for iOS Developer's Guide

Turn-by-Turn Navigation for Walking and Driving

Note: [Important] Application developers using Turn-by-turn Guidance APIs are required to thoroughly test their applications in all expected usage scenarios to ensure safe and correct behavior. Application developers are responsible for warning app users of obligations including but not limited to:
  1. Do not follow instructions that may lead to an unsafe or illegal situation.
  2. Obey all local laws.
  3. Be aware that using a mobile phone or some of its features while driving may be prohibited.
  4. Always keep hands free to operate the vehicle while driving.
  5. The first priority while driving should be road safety.

SDK for iOS supports navigation on pedestrian, car, and truck routes. Using this feature, your app can check the current device position against a calculated route and provide just-in-time navigational instructions, both as visual and voice. Two navigation modes are supported for walking and driving: Turn-by-Turn Navigation Mode, which takes the calculated route and matches the current position against the route, and Tracking Mode, which only tracks the current position without using a route. In Tracking Mode no voice instructions are provided. For more information on voice instructions please see Voice Instructions.

Note: Your application should switch to the navigation-specific map schemes while performing car or pedestrian navigation. For more information on using these schemes see Map Schemes.
Figure 1. Turn-by-Turn Navigation with Speed Warning

Navigation Example on GitHub

You can find an example that demonstrates this feature at https://github.com/heremaps/ (Obj-C) and https://github.com/heremaps/ (Swift).

Navigation rerouting

If you are using Turn-by-Turn Navigation for driving, you have to implement rerouting delegate methods to display actual NMAMapRoute on NMAMapView object. The rerouting is triggered when navigation manager has determined deviation between the route and actual user position. Navigation manager triggers the following methods:
  • navigationManager:navigationManagerWillReroute: - when rerouting is triggered.
  • navigationManager:didRerouteWithError: - when attempt to reroute finished (it doesn't guarantee that new route was created).
  • navigationManager:didUpdateRouteWithResult: - when a change is made to the route being navigated.
The navigationManager:didUpdateRouteWithResult: is the main place for NMAMapRoute redraw. This method might be called in different scenarios:
  • User changed route programatically using
    [[NMANavigationManager sharedNavigationManager] setRoute:newRoute];
  • After successfully rerouting due to deviation between navigation route and actual user position.
  • When navigation is stopped.
The following code is an example of an navigationManager:didUpdateRouteWithResult: implementation:
- (void)navigationManager:(nonnull NMANavigationManager *)navigationManager
 didUpdateRouteWithResult:(nonnull NMARouteResult *)routeResult
{
  if (routeResult && routeResult.routes.count > 0) {
    // Let's add the 1st result onto the map
    self.route = routeResult.routes[0];

    // remove previously created map route from map
    if (self.mapRoute) {
      [self.mapView removeMapObject:self.mapRoute];
    }
    // create new one based on provided route
    if (route) {
      self.mapRoute = [NMAMapRoute mapRouteWithRoute:self.route];
      self.mapRoute.traveledColor = [UIColor clearColor];
      [self.mapView addMapObject:self.mapRoute];
    }
  } else {
    // The routeResult doesn't contain route for redraw.
    // It might occur when navigation stop was called.
  }
}
        

Background Navigation

If you are using the Turn-by-Turn Navigation Mode for driving, you can also set HERE SDK to perform guidance (including voice instructions and event callbacks) while the app is in the background. However, there are a few limitations that you should be aware of:
  • Unlike the foreground navigation scenario, HERE SDK does not stream map data during background navigation. To support background navigation, HERE requires preloading map data (such as for the current city or state) using NMAMapLoader if your app may be used in the background.
  • You cannot render a map (e.g. send it to an external device) when the app is in the background.
  • Navigation cannot be started from the background unless this has been previously enabled while the app is in the foreground. Therefore, an app that launches directly to the background cannot reliably launch a navigation session. For more information about this check backgroundNavigationStartEnabled property on the NMANavigationManager class.

To enable this feature, perform the following steps:

  1. In Xcode Capabilities tab enable Background Modes and check the following entries:
    • Audio and AirPlay
    • Location updates
    Figure 2. Background Modes option in Xcode
  2. Next, turn on background navigation in NMANavigationManager:
    [NMANavigationManager sharedNavigationManager].backgroundNavigationEnabled = YES;

NMANavigationManager Class

NMANavigationManager class is responsible for providing voice and visual instructions to the user while driving or walking. The Navigation Manager is a singleton class, and the singleton instance can be accessed using [NMANavigationManager sharedNavigationManager].

You can start navigation using the following methods:
  • startTurnByTurnNavigationWithRoute: - Starts the Navigation Manager in Navigation Mode
  • startTrackingWithTransportMode: - Starts the Navigation Manager in Tracking Mode
Note:
  • Navigation operations require device positioning. When navigation is started in the Navigation Manager, the NMAPositioningManager is also started automatically. By using NMAPositioningManager with a position data log, HERE SDK can perform a simulated navigation session. For more details on using simulated position data consult Basic Positioning.
  • HERE SDK may not start voice guidance immediately if the user is far from a road when Turn-by-Turn Navigation Mode begins. Your application should display a message such as "head to the nearest road" until voice guidance begins.

NMANavigationManager also provides relevant information that your application can display during a navigation session such as distances, upcoming maneuvers, and average travel speed. Upcoming maneuvers are represented by currentManeuver and nextManeuver properties. currentManeuver represents the most immediate upcoming maneuver while nextManeuver represents the next most immediate upcoming maneuver. Maneuvers contain road-related information such as road name, the turn to be taken, and the maneuver orientation.

currentManeuver and nextManeuver may not be always readily available. You can use navigationManager:hasCurrentManeuver:nextManeuver: method in the NMANavigationManagerDelegate protocol to receive notifications when maneuvers have been updated. For more information see the section about NMANavigationManagerDelegate.

You can take advantage of lowSpeedOffset, highSpeedOffset, speedBoundary, and speedWarningEnabled properties to set up the speed warning feature. When speed warning is enabled, navigationManager:didUpdateSpeedingStatus:forCurrentSpeed:speedLimit notification is sent to the navigation manager delegate when the boundary plus an offset has been violated. The speed warning feature is enabled by default.

Map Tracking

NMANavigationManager also provides properties for customizing map tracking. Map tracking refers to the ability for the map location to be automatically updated during navigation. By default, the map tracking feature is enabled but it can be toggled through mapTrackingEnabled property. When tracking is enabled, you can use mapTrackingOrientation property to set whether the map is oriented dynamically or always pointed North. You can also set whether the map automatically adjusts the zoom level, based on the current device speed, by using mapTrackingAutoZoomEnabled property. By default dynamic orientation and auto zoom are enabled.

After starting NMANavigationManager in Navigation or Tracking mode, you can move the positionIndicator closer to the bottom of the screen by changing transformCenter property in NMAMapView. Having the transformCenter at the bottom of the screen ensures that the route and turning animations are more visible to the user.

Natural Guidance

NMANavigationManager setNaturalGuidanceMode: method can be used to enable natural guidance. Natural guidance refers to a type of dynamic information available during navigation where route guidance instructions contain contextual elements around a decision point. These contextual elements may include services, cartographic features, traffic signals. Some examples of natural guidance instructions are:
  • "Go past the park on your right, then turn left at Anderson school on Bayview street"
  • "Go through the traffic light and turn right before the petrol station"
  • "Continue on your route passing the dome building on your right"

The available types of natural guidance information are defined by NMANaturalGuidanceOption enum. These options may be used individually or in combination, although typically only a single type of guidance instruction would be given for a particular maneuver. To disable natural guidance, pass NMANaturalGuidanceNone to setNaturalGuidanceMode: method.

Note: While using NMANaturalGuidanceLandmark option, the device locale and navigation voice package language should be set to match the user's physical location. Otherwise, landmark information may not be spoken. For example, while navigating in a country that uses French as its spoken language, the voice package and the device locale should be set to French.

NMANavigationManagerDelegate protocol

NMANavigationManager notifies the client of navigation events through its delegates that implement the NMANavigationManagerDelegate protocol. The delegate protocol includes the following methods:
  • navigationManagerDidReachDestination: - Signifies that the destination of navigation was reached
  • navigationManager:hasCurrentManeuver:nextManeuver: - Signifies that there is new instruction information available that can be fetched by accessing nextManeuver property in NMANavigationManager
  • navigationManager:didUpdateRoute: – Provides the newly calculated NMARoute object which can be used to render a new route on the map
  • didUpdateSpeedingStatus:forCurrentSpeed:speedLimit: - Signifies that the user has exceeded the speed limit with the road name and speed limit provided
  • navigationManagerDidLosePosition: - Signifies that the system has lost its GPS signal
  • navigationManagerDidFindPosition: - Signifies that the system has acquired a GPS signal
  • navigationManagerWillReroute: – Signifies that a route recalculation has begun. This is a result of the current position deviating from the original route
  • navigationManagerDidReroute: - Signifies that a route recalculation has finished
  • navigationManager:didFindAlternateRouteWithResult: - Signifies that the navigation manager has found an improved route
  • navigationManager:shouldPlayVoiceFeedbackWithText: - Signifies that a voice feedback is ready to be played. Use this callback return values to retrieve the text to be spoken (if applicable) and to control whether the current voice feedback should be played
  • navigationManager:willPlayVoiceFeedbackWithText: - Signifies that a voice feedback event will occur (for example, when a maneuver is being announced)
  • navigationManager:didPlayVoiceFeedbackWithText: - Signifies that a voice feedback event has finished
  • navigationManager:didFindAlternateRoutes: - Signifies that alternative routes have been found during navigation with traffic avoidance mode enabled

Lane Information

The NMANavigationManagerDelegate also provides navigationManager:didUpdateLaneInformation:roadElement: method. This callback occurs when the user has arrived at a point in the route where lane information should be presented, such as before a highway exit. The NMALaneInformation class represents a lane turn direction and whether this lane is on the current route. For example, an application may receive navigationManager:didUpdateLaneInformation:roadElement: callback as the user navigates to an intersection. If the route requires a left turn and the current road has three lanes — a left-turn lane and two straight lanes — then the callback contains three NMALaneInformation objects. Since NMALaneInformation objects are always returned in the callback method in a left-to-right order, the first NMALaneInformation has a directions property as "left" and recommendationState property, which indicates whether the lane is on the current route. If there isn't enough data to determine whether the lane is on or off-route, recommendationState property returns NMALaneInformationRecommendationStateNotAvailable.

Note: Information about lanes requires extra map data for a route. The application must first download the required map data using NMAMapDataPrefetcher or NMAMapLoader. Otherwise, lane information will not be returned properly.

School zone

NMASchoolZoneWarnerDelegate provides callback methods to check whether there is school zone ahead, whether user enters or leaves school zone. Callback didDetectSchoolZone occurs when there is school zone ahead if user follows current route direction, it will be triggered in about 100 meters before each NMARoadElement with school zone. Callback didUpdateSchoolZone occurs either when user entered school zone or left. For example:

- (void)schoolZoneWarner:(nonnull NMASchoolZoneWarner *)schoolZoneWarner
   didDetectSchoolZone:(nonnull NMASchoolZoneNotification *)notification
{
  // distance to the road element with school zone
  NSUInteger distance = notification.distance;
  // road element associated with this school zone
  NMARoadElement* roadElement = notification.roadElement;
  // begin time, e.g. Monday 09:00
  NSDate* timeBegin = notification.schoolZoneInfo.timeBegin;
  // end time, e.g. Monday 17:00
  NSDate* timeEnd = notification.schoolZoneInfo.timeEnd;
  float speedLimit = notification.schoolZoneInfo.speedLimit;
}

- (void)schoolZoneWarner:(nonnull NMASchoolZoneWarner *)schoolZoneWarner
   didUpdateSchoolZone:(nonnull NMASchoolZoneInfo *)zoneInfo
{
  if (zoneInfo) {
    // user enters school zone
    float speedLimit = zoneInfo.speedLimit;
  } else {
    // user left school zone
  }
}
        
Developer can also use utility methods from NMASchoolZoneWarnerDelegate to check whether specific road element has school zone. For example:

 // Get road element from geo coordinate
 // Use instance of NMAMapView to get roadElementAtCoordinates
NMARoadElement* roadElement = [NMAMapView roadElementAtCoordinates:coordinate];
 if (roadElement) {
   // Check whether road element has active school zone
   NMASchoolZoneInfo* info = [NMASchoolZoneWarner schoolZoneInfoForRoadElement:roadElement];
   if (info) {
     // provided road element has school zone
   }

   // Check whether school zone is active at specific time
   // GMT: Sunday, 8 March 2020, 00:00:00
   NSDate *sunday = [NSDate dateWithTimeIntervalSince1970:1583625600];
   NMASchoolZoneInfo* infoAtTime = [NMASchoolZoneWarner schoolZoneInfoForRoadElement:roadElement
                                          time:sunday];
   if (infoAtTime) {
     // school zone is active at provided time
   }
 } else {
   // NMARoadElement is nil either because there is no road at the provided location or map
   // data is not loaded. Use NMAMapLoader API to download map area, or use road element from
   // another provider, e.g. from the calculated route.
 }
        

Realistic View: 2D Signposts and Junction View

In addition to the data offered through the Lane Info feature, your application can also use SDK for iOS to offer image previews of signposts and junctions on certain highways. For example, as a user approaches a fork on a highway, your application can show a preview of two instruction signs above the highway and the lanes near the junction with indicator arrows highlighting the correct lanes. These image previews are known as 2D Signposts and Junction View, and together they are known as Realistic View.

Figure 3. An Example of a 2D Signpost
Figure 4. An Example of a Junction View

The Realistic View feature is disabled by default. To enable it, use NMANavigationManager.realisticViewMode property and set the view mode to NMARealisticViewDay or NMARealisticViewNight. Next, register the desired image aspect ratios by using NMANavigationManager.realisticViewAspectRatios property.

After adding your delegate implementation, your application begins receiving the following method callbacks as the user approaches a highway section that supports Realistic View. The next maneuver callback occurs when a realistic view is available in the second upcoming maneuver (for example, if the next maneuver is to enter a junction), and the current maneuver callback occurs as the most immediate upcoming maneuver is entered (for example, if the user is entering the junction).
  • navigationManager:didUpdateRealisticViewsForCurrentManeuver:
  • navigationManager:didUpdateRealisticViewsForNextManeuver:
The first two method callbacks mentioned above return an NSDictionary object named realisticViews, which holds one or more NSDictionary of images. To retrieve the NSDictionary of images from realisticViews, use one of the following aspect ratio strings as the key:
  • NMARealisticView16x9Key
  • NMARealisticView3x5Key
  • NMARealisticView4x3Key
  • NMARealisticView5x3Key
After performing this step, you can extract the signpost and junction view images from the NSDictionary through NMANavigationManagerSignpostKey and NMANavigationManagerJunctionViewKey keys.
Note: It is possible to add multiple aspect ratios and receive multiple images of the same signpost or junction view. However, please be aware that this may cause some performance impact.
Note: To dismiss the Realistic View images, your navigation manager delegate should also implement and listen for navigationManagerDidInvalidateRealisticViews: method. This method is called when realistic view images should be dismissed (for example, after the user has entered the junction).

The following is an example of a navigationManager:didUpdateRealisticViewsForCurrentManeuver: implementation:


- (void)navigationManager:(NMANavigationManager *)navigationManager
    didUpdateRealisticViewsForCurrentManeuver:(NSDictionary *)realisticViews
{
  NSDictionary *realisticView = [realisticViews objectForKey:NMARealisticView3x5Key];
  NMAImage *junction = [realisticView objectForKey:NMANavigationManagerJunctionViewKey];
  if (junction) {
    //** display the junction image
  }
  NMAImage *signpost = [realisticView objectForKey:NMANavigationManagerSignpostKey];
  if (signpost) {
    //** display the signpost image
  }
}