Expand Minimize Picture-in-picture Power Device Status Voice Recognition Skip Back Skip Forward Minus Plus Play Search
Internet Explorer alert
This browser is not recommended for use with smartdevicelink.com, and may not function properly. Upgrade to a different browser to guarantee support of all features.
close alert
To Top Created with Sketch. To Top
To Bottom Created with Sketch. To Bottom
iOS Guides


Mobile navigation allows map partners to easily display their maps as well as present visual and audio turn-by-turn prompts on the head unit.

Navigation apps have different behavior on the head unit than normal applications. The main differences are:

  • Navigation apps don't use base screen templates. Their main view is the video stream sent from the device.
  • Navigation apps can send audio via a binary stream. This will attenuate the current audio source and should be used for navigation commands.
  • Navigation apps can receive touch events from the video stream.

Configuring a Module to Stream

In order to view the stream, you need a head unit to connect with that supports streaming. If this is a physical module created by an OEM, such as a Ford TDK, you may need special permissions from that OEM to test streaming. Physical modules often have strict permissions and/or encryption requirements to stream.

The alternative is to stream over TCP to open-source Core. For more details on setting up open-source Core and an HMI, see the Install and Run guide, and to set up video streaming for that Core and HMI, see the Audio and Video Streaming guide. We recommend using the built-in Generic_HMI server streaming instead of GStreamer socket or pipe streaming.

Configuring a Navigation App

The basic connection setup is similar for all apps. Please follow the Integration Basics guide for more information.

In order to create a navigation app an appType of SDLAppHMITypeNavigation must be set in the SDLManager's SDLLifecycleConfiguration.

The second difference is that a SDLStreamingMediaConfiguration must be created and passed to the SDLConfiguration. A property called securityManagers must be set if connecting to a version of Core that requires secure video and audio streaming. This property requires an array of classes of security managers, which will conform to the SDLSecurityType protocol. These security libraries are provided by the OEMs themselves, and will only work for that OEM. There is no general catch-all security library.

SDLLifecycleConfiguration* lifecycleConfig = [SDLLifecycleConfiguration defaultConfigurationWithAppName:@"<#App Name#>" fullAppId:@"<#App Id#>"];
lifecycleConfig.appType = SDLAppHMITypeNavigation;

SDLEncryptionConfiguration *encryptionConfig = [[SDLEncryptionConfiguration alloc] initWithSecurityManagers:@[OEMSecurityManager.self] delegate:self];
SDLStreamingMediaConfiguration *streamingConfig = [SDLStreamingMediaConfiguration secureConfiguration];
SDLConfiguration *config = [[SDLConfiguration alloc] initWithLifecycle:lifecycleConfig lockScreen:[SDLLockScreenConfiguration enabledConfiguration] logging:[SDLLogConfiguration defaultConfiguration] streamingMedia:streamingConfig fileManager:[SDLFileManagerConfiguration defaultConfiguration] encryption:encryptionConfig];
let lifecycleConfig = SDLLifecycleConfiguration(appName: "<#App Name#>", fullAppId: "<#App Id#>")
lifecycleConfig.appType = .navigation

let encryptionConfig = SDLEncryptionConfiguration(securityManagers: [OEMSecurityManager.self], delegate: self)
let streamingConfig = SDLStreamingMediaConfiguration.secure()
let config = SDLConfiguration(lifecycle: lifecycleConfig, lockScreen: .enabled(), logging: .default(), streamingMedia: streamingConfig, fileManager: .default(), encryption: encryptionConfig)

When compiling your app for production, make sure to include all possible OEM security managers that you wish to support.

Preventing Device Sleep

When building a navigation app, you should ensure that the device never sleeps while your app is in the foreground of the device and is in an HMI level other than NONE. If your device sleeps, it will be unable to stream video data. To do so, implement the following SDLManagerDelegate method.

- (void)hmiLevel:(SDLHMILevel)oldLevel didChangeToLevel:(SDLHMILevel)newLevel {
    if (![newLevel isEqualToEnum:SDLHMILevelNone]) {
        [UIApplication sharedApplication].idleTimerDisabled = YES;
    } else {
        [UIApplication sharedApplication].idleTimerDisabled = NO;
func hmiLevel(_ oldLevel: SDLHMILevel, didChangeToLevel newLevel: SDLHMILevel) {
    if newLevel != .none {
        UIApplication.shared.isIdleTimerDisabled = true
    } else {
        UIApplication.shared.isIdleTimerDisabled = false

Keyboard Input

To present a keyboard (such as for searching for navigation destinations), you should use the SDLScreenManager's keyboard presentation feature. For more information, see the Popup Keyboards guide.

Head units supporting RPC v6.0+ may support navigation-specific subscription buttons for the navigation template. These subscription buttons allow your user to manipulate the map using hard buttons located on car's center console or steering wheel. It is important to support these subscription buttons in order to provide your user with the expected in-car navigation user experience. This is especially true on head units that don't support touch input as there will be no other way for your user to manipulate the map. See Template Subscription Buttons for a list of these navigation buttons.

When to Cancel Your Route

Between your navigation app, other navigation apps, and embedded navigation, only one route should be in progress at a time. To know when the embedded navigation or another navigation app has started a route, create a navigation service and when your service becomes inactive, your app should cancel any active route.

[self.sdlManager.systemCapabilityManager subscribeToCapabilityType:SDLSystemCapabilityTypeAppServices withUpdateHandler:^(SDLSystemCapability * _Nullable capability, BOOL subscribed, NSError * _Nullable error) {
    SDLAppServicesCapabilities *serviceCapabilities = capability.appServicesCapabilities;
    for (SDLAppServiceCapability *serviceCapability in serviceCapabilities.appServices) {
        if ([serviceCapability.updatedAppServiceRecord.serviceManifest.serviceName isEqualToString:<#Your service name#>]) {
            if (!serviceCapability.updatedAppServiceRecord.serviceActive) {
                // Cancel your active route
sdlManager.systemCapabilityManager.subscribe(capabilityType: .appServices) { (systemCapability, subscribed, error) in
    guard let serviceCapabilities = systemCapability?.appServicesCapabilities?.appServices else { return }
    for serviceCapability in serviceCapabilities {
        if serviceCapability.updatedAppServiceRecord.serviceManifest.serviceName == <#Your service name#> {
            if !serviceCapability.updatedAppServiceRecord.serviceActive.boolValue {
                // Cancel your active route
View on GitHub.com
Previous Section Next Section