Skip to content

Navigation

This section explains the implementation of real time turn-by-turn navigational instructions, both as visual and voice instructions.

Show location on map

First, add location usage description to Info.plist (Privacy - Location When In Use Usage Description):

<key>NSLocationWhenInUseUsageDescription</key>
<string>Show location on the map, guide along the route.</string>

Based on the example from Getting Started, current device location can be shown on SYMapView by adding this code to ViewController.

import CoreLocation

class ViewController: UIViewController {
    let locationManager = CLLocationManager()

    // ...

    func setupMapView() {
        // create SYMapView
        // ...

        // 1 - connect camera to GPS location
        mapView.camera.movementMode = .followGpsPosition

        // 2 - make SDK listen to location updates
        SYPositioning().startUpdatingPosition()

        // 3 - ask for GPS location permissions, Sygic Maps SDK doesn't do this request itself
        if locationManager.authorizationStatus == .notDetermined {
            locationManager.requestWhenInUseAuthorization()
        }
    }
}

Start navigating

The Sygic Maps SDK for iOS supports navigation on pedestrian and car 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 instructions. Turn-by-Turn Navigation Mode, which takes the calculated route and matches the current position against the route is supported for walking and driving.

Expanding our example from route calculation (see Routing section)

let navigationObserver = SYNavigationObserver()
func startNavigation(with route: SYRoute) {
    // Make self as delegate to receive and handle SYNavigationDelegate calls
    navigationObserver.delegate = self

    // Start navigation with route which you got from Route computing (see SYRouting)
    SYNavigationManager.sharedNavigation().startNavigation(with: route)

    // Optionally: Set cameraMovemementMode (e.g. followGpsPosition to move map when vehicle moves)
    // Start following user's position using gps signal
    SYPositioningManager.shared()?.dataSource = SYRoutePositionSimulator(route: route)
    SYPositioningManager.shared()?.dataSource?.start()
    self.mapView?.camera.movementMode = SYCameraMovement.followGpsPositionWithAutozoom
    self.mapView?.camera.rotationMode = SYCameraRotation.vehicle
    self.mapView?.camera.tilt = 70
    self.mapView?.camera.zoom = 18
}

SYNavigationDelegate protocol

SYNavigation notifies the client of navigation events through its delegates that implement the SYNavigationDelegate protocol. The delegate protocol include methods such as:

  • didUpdateSpeedLimit - Called when the speed limit has changed.
  • didUpdateDirection - Called when current instruction has changed.
  • didUpdateSignpost - Called that the signopostInfo has changed.
  • didUpdateIncident - Called that the incident on the route has been updated.
  • didUpdateRailwayCrossing - Called when current route railway crossing has changed.
  • didUpdateSharpCurve - Called when a danger turn is ahead on current route.
  • didPassWaypointWithIndex - Called when turn-by-turn navigation waypoint is passed.
  • navigationManagerDidReachFinish - Called when turn-by-turn navigation destination is reached.
  • didFindBetterRoute - Called when better route has been found.
  • didUpdateHighwayExit - Called when highway exit info has changed. Event does not fire when route is calculated.
  • didUpdateRecomputeProgress - Called when current navigation route starts recomputing.
  • didUpdatePlace - Called when places on current navigation route have changed.
  • didUpdateLane - Called when lane information on current navigation route has changed.
  • didUpdateTraffic - Called when traffic on the current navigation route is changed.

This method will only be called when SYNavigationManager is navigating a route using a transport mode of SYTransportModeCar and SYTraffic.trafficServiceEnabled.

  • didUpdateRoute - Called when current navigation route is changed or removed.
  • didUpdateBatteryCapacity - Called when the battery capacity has been changed (new in SDK 17).
  • didFindWaypointOutOfRange - Called when charging waypoint on route is out of range from your position (New in SDK 17).

SYNavigationAudioFeedbackDelegate protocol

To get audio notifications and voice navigation, you have implement SYNavigationAudioFeedbackDelegate. If it's not implemented, voice guidance and audio warnings will be disabled. SYNavigationAudioFeedbackDelegate can allow/disallow playback of every single sound from SDK depend on its type or other circumstances.

SYNavigationManager.sharedNavigation().audioFeedbackDelegate = self

// ...

extension MyClass: SYNavigationAudioFeedbackDelegate {
    func navigation(_ navigation: SYNavigationManager, shouldPlayInstructionAudioFeedback instruction: SYDirectionInfo) -> Bool {
        true
    }
}

then

  • shouldPlayRailwayAudioFeedback - Called when railway crossing has warning audio feedback is ready to play.
  • shouldPlaySharpCurveAudioFeedback - Called when sharp curve warning audio feedback is ready to play.
  • shouldPlayIncidentAudioFeedback - Called when incident warning audio feedback is ready to play.
  • shouldPlaySpeedLimitAudioFeedback - Called when speed limit warning audio feedback is ready to play.
  • shouldPlayBetterRouteAudioFeedback - Called when better route audio feedback is ready to play.
  • shouldPlayTrafficAudioFeedback - Called when traffic change audio feedback is ready to play.
  • shouldPlayInstructionAudioFeedback - Called when navigation instruction audio feedback is ready to play.

Audio Warnings

Sygic Maps SDK enables you to set custom audio notifications for warnings. If the methods of above mentioned SYNavigationAudioFeedbackDelegate are set to true, there will be played some default set audio notifications. To use your custom ones, you have to use SYAudioSettings class. SYAudioSettings class enables to set custom voice for various cases. You can choose between prerecorded audio files (OGG or WAVE format) or TTS voice. See the SYAudioSettings API reference for more info.

Following example shows, how to set an custom TTS voice, when you exceed the speed limit.

let audioSettings = SYSpeedLimitAudioWarningSettings()
audioSettings.mode = .useTts
audioSettings.ttsText = "Slow down!"

If you would like to use custom pre-recorded audio file, you need to choose it from path:

let audioSettings = SYAudioSettings()
audioSettings.speedLimitWarning.warningSoundPath = Bundle.main.path(forResource: "/example/example/example", ofType: "wav")

Voice Instructions

Voice instructions are available in the Sygic Maps SDK as voice packages. Voice packages are available in two forms: pre-packaged or downloadable through the voice catalog. You can set a voice package to be used for navigational instructions. However, if a package is not set, the Sygic Maps SDK sets the navigation voice language to US English, which is pre-packaged with the Sygic Maps SDK.

The SYVoicePackage class encapsulates spoken voices that can be used for navigation guidance. It contains information such as name, gender, and the spoken language. This information can be accessed through its class properties.

A list of loaded SYVoicePackage instances can be accessed by using the SYVoiceCatalog singleton instance. Multiple voice package can be loaded to the device, but only one can be selected for navigation voice playback. A SYVoicePackage can be used through the voicePackage property. Each SYVoicePackage is represented by a unique ID in the packageId property.

The Sygic Maps SDK supports two types of voice packages: text-to-speech or pre-recorded. Pre-recorded voices provide basic maneuver instructions, such as "turn right in 100 meters" instruction, while text-to-speech voices also support spoken street names, such as "turn right in 100 meters onto Wall Street" instruction.

The following is an example of how to use a SYVoicePackage with the navigation manager:

class ViewController: UIViewController, SYVoiceCatalogDelegate {
    var voicePackages: [SYVoicePackage] = []

    func initMap() {

      //..
      // after SDK is successfully initialized (see SDK Initialization chapter)

      // Make self as delagate for SYVoiceCatalog to receive and handle responses.
      SYVoiceCatalog.shared()?.delegate = self

      // Get a list of all available and already installed voice packages
      SYVoiceCatalog.shared()?.getAvailableVoicePackages { (_, availablePackages) in
          // voicePackages contains installed packages and packages available to install from server
          self.voicePackages = availablePackages
      }

      // Optionally: If you want just installed packages
      SYVoiceCatalog.shared()?.getInstalledPackages { (_, installedPackages) in
          self.voicePackages = installedPackages
      }
    }

    // Call this method to download desired voice package
    func downloadPackage(with index: Int) {
        if index < self.voicePackages.count {
            let voicePackage = self.voicePackages[index]
            // Download and install voice package to device
            SYVoiceCatalog.shared()?.installVoicePackage(voicePackage)
        }
    }

    // MARK: - SYVoiceCatalogDelegate

    // Called when voice package was successfully installed.
    func voiceCatalog(_ voiceCatalog: SYVoiceCatalog, didInstallVoicePackage package: SYVoicePackage, result: SYPackageInstallResult, from task: SYTask) {
        // Set the downloaded voice as your current
        SYVoiceCatalog.shared()?.setCurrentVoice(voicePackage)
    }
}

If the voice is set, in navigation mode the voice instructions are played automatically.

This is a list of the potential TTS languages that are supported. Actual audio playback depends on the supported languages in the user's installed version of iOS.

  • English (US)
  • English (UK)
  • English (AUS)
  • French (France)
  • French (Canada)
  • German
  • Belgian
  • Bahasa Indonesia
  • Hungarian
  • Dutch
  • Arabic
  • Finnish
  • Spanish (Spain)
  • Spanish (Mexico)
  • Italian
  • Norwegian
  • Portuguese (Portugal)
  • Portuguese (Brazil)
  • Russian
  • Swedish
  • Finnish
  • Danish
  • Korean
  • Hindi
  • Chinese (Taiwanese Mandarin)
  • Chinese (Hong Kong Mandarin)
  • Turkish
  • Czech
  • Polish

Traffic

The Sygic Maps SDK for iOS offers real-time traffic flow and congestion overlays. Traffic information can be displayed on the SYMapView (where available) by calling the enableTraffic method. While the Sygic Maps SDK requires a network data connection to download real time traffic information, the visualization may continue to be displayed even if a connection is lost - until the traffic events expire, or the visibility is toggled.

Info

Please note that if your license does not contain traffic, you will not receive any traffic information.

// To enable (or disable) traffic
SYTraffic.shared().trafficServiceEnabled = true // or false

Map view with traffic

For further information see the SYTraffic reference.

Signposts

This section provides guidelines on how to use the Sygic Maps SDK Signpost object to present visual maneuver instructions which match with the audible voice instruction during turn-by-turn guidance. Signs represent textual and graphic information posted along roads. The information is always represented as text, but may originate from a graphical icon. Signpost information may be used for route guidance (both audible and visual guidance) and map display. A navigation system may prefer using the signpost text rather than the street/ramp name as the latter may not always match what is on the sign in reality and may confuse a user. The signpost feature supports the user navigating through complex situations and provides a conformation for a maneuver by presenting the same direction information as shown on the street signs in reality.

Based on the map attributes, the Sygic Maps SDK for iOS aggregate the following information into a Signpost object:

  • Route number
  • Exit number
  • Exit name
  • Pictogram
  • Place name

Following example shows, how to get these information from the data structure, which the iOS SDK offers.

class Viewcontroller: UIViewController, SYNavigationDelegate {
    let route = SYRoute()

    // ...

    let navigationObserver = SYNavigationObserver()
    override func viewDidLoad() {
        // Make self a delegate for SYNavigation to receive signpost informations
        navigationObserver.delegate = self
        // Start navigation with your route (for details how to compute route and start navigation see Navigation and Routing sections)
        SYNavigationManager.sharedNavigation().startNavigation(with: route)
    }

    // MARK: - SYNavigationDelegate

func navigation(_ observer: SYNavigationObserver, didUpdateSignpost signpostInfo: [SYSignpostInfo]?) {
        // Get first signpost from signpostInfo array
        guard let firstSignpost = signpostInfo?.first else { return }

        // Text color of the signpost
        let textColor = firstSignpost.textColor
        // Background color of the signpost
        let backgroundColor = firstSignpost.backgroundColor
        // Distance to signpost from current position
        let distanceToSignpost = firstSignpost.distance


        // Single signpost contains multiple SYSignpostElement objects which contains detail informations about specific signpost
        for element in firstSignpost.elements {
            switch element.type {
            case .placeName, .streetName, .otherDestination:
                if let text = element.text {
                    // Name of place, street or other destination
                }
            case .routeNumber:
                if let routeNumber = element.text {
                    // Route number
                }
            case .exitName:
                if let exitName = element.text {
                    // Exit name
                }
            case .exitNumber:
                if let number = element.text {
                    // Exit number
                }
            case .pictogram:
                // Pictogram (e.g. Airport, Hospital, ...)
                let pictogram = element.pictogram
            case .lineBreak:
                break
            }
        }
    }
}

Directions

To provide more detailed information in signpost, you can display the direction which the user should follow. The Directions feature allows developers to define and display routes between a start and a destination point within their application. SYNavigationObserver can return following information:

  • Direction distance
  • Next direction distance
  • Maneuver type - see the all available ManeuverTypes
  • Road name
  • Next road name

Following example shows, how to get these information from the data structure, which the iOS SDK offers.

class Viewcontroller: UIViewController, SYNavigationDelegate {
    let route = SYRoute()

    // ...

    let navigationObserver = SYNavigationObserver()
    override func viewDidLoad() {
        // Make self a delegate for SYNavigation to receive direction informations
        navigationObserver.delegate = self
        // Start navigation with your route (for details how to compute route and start navigation see Navigation and Routing sections)
        SYNavigationManager.sharedNavigation().startNavigation(with: route)
    }

    // MARK: - SYNavigationDelegate

    func navigation(_ observer: SYNavigationObserver, didUpdateDirection instruction: SYDirectionInfo?) {
        guard let instruction = instruction else { return }

        if let primaryManeuver = instruction.primaryManeuver {
            let distanceToManeuver = primaryManeuver.distanceToManeuver // in meters
            let instructionType = primaryManeuver.type // e.g. left, right, straight, u-turn, ...
            let currentRoadName = primaryManeuver.road?.roadName
            let nextRoadName = primaryManeuver.nextRoad?.roadName

            print("Distance to instruction of type \(instructionType) on the road \(currentRoadName) is \(distanceToManeuver). Next road is \(nextRoadName)")
        }1

        // Optionally: handle secondary maneuver similar like the primary one
        if let secondaryManeuver = instruction.secondaryManeuver {

        }
    }
}

With these data now you just have to draw them into your view and create your own signposts and directions. For example like this:

Signpost

Junction View

Junction view is one of our advanced safety features. When you are approaching a complex highway intersection, a full screen diagram of the intersection will appear on the screen showing you in detail which lane you should be in. It guides you into the correct lane to make driving easier, safer and less stressful.

class NaviViewcontroller: UIViewController, SYNavigationDelegate {
    let route = SYRoute()

    // ...

    let navigationObserver = SYNavigationObserver()
    override func viewDidLoad() {
        // Make self a delegate for SYNavigation to receive direction informations
        navigationObserver.delegate = self
        // Start navigation with your route (for details how to compute route and start navigation see Navigation and Routing sections)
        SYNavigationManager.sharedNavigation().startNavigation(with: route)
    }

    // MARK: - SYNavigationDelegate

    func navigation(_ observer: SYNavigationObserver, didUpdateSignpost signpostInfo: [SYSignpostInfo]?) {
        // Get junctionInfo from first signpost if available
        guard let junctionInfo = signpostInfo?.first?.junctionInfo else { return }

        let turnType = junctionInfo.turnType // e.g. exit, bifurcation, road exit
        let turnDirection = junctionInfo.turnDirection // left, right or none
        let fromLanes = junctionInfo.fromLanesCount // number of lanes before junction
        let toLanesLeft = junctionInfo.toLeftLanesCount // number of lanes on the left side after junction
        let toLanesRight = junctionInfo.toRightLanesCount // number of lanes on the right side after junction

        // Optionally: get background type of upcoming junction info (e.g. city or forest)
        let background = junctionInfo.background
    }

}

Speed Limit

Speed limits indicate the legal speed for a vehicle. Depending on the country the values are given in mph or kph.

Following example shows, how to get the current speed limit and it properties.

class NaviViewcontroller: UIViewController, SYNavigationDelegate {
    let route = SYRoute()

    // ...

    let navigationObserver = SYNavigationObserver()
    override func viewDidLoad() {
        // Make self a delegate for SYNavigation to receive direction informations
        navigationObserver.delegate = self
        // Start navigation with your route (for details how to compute route and start navigation see Navigation and Routing sections)
        SYNavigationManager.sharedNavigation().startNavigation(with: route)
    }

    // MARK: - SYNavigationDelegate

    func navigation(_ observer: SYNavigationObserver, didUpdateSpeedLimit limit: SYSpeedLimitInfo?) {
        guard let limit = limit else { return }

        let maximumAllowedSpeed = limit.speedLimit // maximum allowed speed
        let isInMunicipality = limit.isInMunicipality // represents if you are heading through Municipality
        let country = limit.country // america or rest of world
        let speedLimitUnits = limit.nativeUnits // kmh or mph
    }
}

Warning Settings

If you want to change the settings to the warnings you get during navigation you can use SYWarningSettings. It's a base class for warning notification settings. To access these settings you have to use [SYNavigationManager.sharedNavigation.settings] instance.

SYPlaceSettings

Change some "POI On Route" settings.

  • maxCount - place on Route max search poi count.
  • maxDistance - place on Route max search distance.
  • categories - list of categories to be notified about.
SYNavigationManager.sharedNavigation().settings.placeOnRoute.maxDistance = 100

SYDirectionSettings

  • nextDirectionDistance - Set the minimal distance between first and second instruction to be notified.
SYNavigationManager.sharedNavigation().settings.direction.nextDirectionDistance = 5

SYSpeedLimitWarningSettings

  • speedLimitDiffInCity - Set diff speed above maximum allowed speed to be notified as speeding in city.
  • speedLimitDiff - Set diff speed above maximum allowed speed to be notified as speeding.
  • nextSpeedLimitDistance - Set next speed limit search distance ahead vehicle.
  • nextSpeedLimitDistanceInCity - Set distance how far will look for other speed limit ahead vehicle in city.
SYNavigationManager.sharedNavigation().settings.speedLimit.speedLimitDiffInCity = 5

SYSpeedCameraWarningSettings

  • searchDistanceInCity - Set Speed cameras search distance ahead vehicle in city.
  • searchDistance - Set Speed cameras search distance ahead vehicle.

SYRailwayCrossingWarningSettings

  • searchDistance - Set Railway crossing search distance ahead vehicle.
SYNavigationManager.sharedNavigation().settings.railwayCrossing.searchDistance = 300

Report Incident

Note

Currently available for iOS.

Our Speed Cameras and Incidents database consists of more than 60 000 fixed speed cameras, red light cameras and average speed checks all over the world. On top of that, the community reports tens of thousands of additional mobile speed cameras and police checks every day.

If you want to improve the database, use the following example to report an incident. As a parameter you can choose in which direction it happened on the road:

  • location - The exact SYGeoCoordinate position of the incident.
  • type - Type of the incident you want to report. See the available SYIncidentType in API reference.
  • direction - Indicates whether the incident happened in my direction or opposite direction.
let coordinate = SYPositioning.shared()?.lastKnownLocation?.coordinate // Get last known position or provide your custom position
let type = SYIncidentType.camera // See SYIncidentType for more options
let direction = SYIncidentDirection.myDirection // or .oppositeDirection
SYNavigation.shared()?.reportIncident(atLocation: coordinate!, type: type, direction: direction)

Vehicle Aid

There's a possibility that you would like to show the upcoming restrictions directly in the map so that the driver sees it and is aware of the road. These restrictions contain types such as whether the road is a blind road, if it is prohibited to turn there, or what the maximum weight is. Since SDK 21.6.0 it is possible to directly add the Vehicle Aid Info object to the map:

import UIKit
import SygicMaps

class YourClass: MapExampleViewController, SYNavigationDelegate {
    let navigationObserver = SYNavigationObserver()
    var vehicleAidMapObjects = [SYMapObject]()
}

extension YourClass {
    func navigation(_ observer: SYNavigationObserver, didNotifyVehicleAid info: [SYVehicleAidInfo]?) {
        vehicleAidMapObjects.removeAll() // remove the already drawn objects so that they are not overdrawn
        info?.forEach({ vehicleAidInfo in
            vehicleAidInfo.restriction // SYRestrictionInfo
            vehicleAidInfo.maneuverPosition // SYGeocoordinates
            vehicleAidInfo.distanceToManeuver // Integer
            // add vehicle aid as MapObject
            let sign = SYMapTrafficSign(vehicleAidInfo: vehicleAidInfo)!
            mapView.add(sign)
            vehicleAidMapObjects.append(sign)
        })
    }
}

Adding custom incidents

Please note that if you define your own incident category, it will be necessary to define a new icon in the skin file, else it won't be displayed. However, if you choose one of the already existing ones, it will display the icon that is already assigned to that incident type. Here's a brief example of how to add your own speed camera:

let incidentId = SYIncidentId(uuid: UUID()) 
let incident = SYIncidentSpeedCamera(id: incidentId,
                                      location: SYGeoCoordinate(latitude: 48.1, longitude: 17.1),
                                      category: SYIncidentTypeRadarMobileSpeed,
                                      validTo: Date()+5000,
                                      heading: SYAngle(349),
                                      bidirectional: true,
                                      speedLimit: 50)

let incidentData = SYIncidentData(incident: incident,
                                  audioNotificationParameters: SYIncidentAudioNotificationParameters(
                                  notificationDistance: 50, urbanNotificationDistance: 50))

SYIncidentsManager.shared()?.addIncidents([incidentData]) { err in

}