Build a navigation app
This tutorial shows how to build a simple navigation application using the TomTom Navigation SDK for iOS. The app uses the built-in UI components. You can also build custom components and integrate them with the SDK.
The application displays a map that shows the current location. After the user selects a destination with a long press, the app plans a route and draws it on the map. Navigation is started automatically using the GPS location or a route simulation.
Project set up
The Navigation SDK for iOS is only available upon request. Contact us to get started.
Install Xcode if you don’t already have it.
Create a new project or open an existing one. The application deployment target has to be set to at least 13.0.
Install Cocoapods on your computer.
Install cocoapods-art tool on your computer.
Because the repository for Navigation SDK is private, you will need to contact us to get access. Once you have obtained access, go to repositories.tomtom.com and log in with your account. Expand the user menu in the top-right corner, and select "Edit profile" → "Generate an Identity Token". Copy your token and put it, together with your login, in
~/.netrc
. If the file doesn’t exist, create one and add the following entry:1machine repositories.tomtom.com2login <YOUR_LOGIN>3password <YOUR_TOKEN>Add a reference to the cocoapods-art repository:
pod repo-art add tomtom-sdk-cocoapods "https://repositories.tomtom.com/artifactory/api/pods/cocoapods"Then create a
Podfile
in the project folder. Thepod init
command in the project folder can generate a basic podfile.At the top of the Podfile add the source of the SDK Cocoapods.
1plugin 'cocoapods-art', :sources => [2 'tomtom-sdk-cocoapods'3]Add the modules that your project requires. This tutorial uses the
TomTomSDKMapsDisplay
,TomTomSDKOnlineRouting
,TomTomSDKRouting
,TomTomSDKNavigationEngine
,TomTomSDKUIComponents
,TomTomSDKSystemTextToSpeechEngine
,TomTomSDKTextToSpeechEngine
andTomTomSDKTextToSpeech
modules.1TOMTOM_SDK_VERSION = '{version}'23target 'YourAppTarget' do4 use_frameworks!5 pod 'TomTomSDKMapsDisplay', TOMTOM_SDK_VERSION6 pod 'TomTomSDKNavigationEngine', TOMTOM_SDK_VERSION7 pod 'TomTomSDKRouting', TOMTOM_SDK_VERSION8 pod 'TomTomSDKOnlineRouting', TOMTOM_SDK_VERSION9 pod 'TomTomSDKUIComponents', TOMTOM_SDK_VERSION10 pod 'TomTomSDKSystemTextToSpeechEngine', TOMTOM_SDK_VERSION11 pod 'TomTomSDKTextToSpeechEngine', TOMTOM_SDK_VERSION12 pod 'TomTomSDKTextToSpeech', TOMTOM_SDK_VERSION13end
Make sure you have the appropriate TomTom API key. If you don’t have an API Key, go to How to get a TomTom API Key to learn how to create one.
Getting started
Create an empty App project with Xcode 13.4 or higher, using a SwiftUI interface that targets iOS 15 and above. Copy the snippets below into the *App.swift
file that Xcode generated for the project.
Create the basic Swift application structure as follows:
1// System modules2import CoreLocation3import Foundation4import SwiftUI56// GO SDK modules7import TomTomSDKCommon8import TomTomSDKLocation9import TomTomSDKMapsDisplay10import TomTomSDKNavigationEngine11import TomTomSDKOnlineRouting12import TomTomSDKRoute13import TomTomSDKRouting14import TomTomSDKSystemTextToSpeechEngine15import TomTomSDKTextToSpeech16import TomTomSDKTextToSpeechEngine17import TomTomSDKUIComponents1819// MARK: - TomTomServices2021enum TomTomServices {22 static func register() {23 TomTomSDKMapsDisplay.MapsDisplayService.mapsKey = Keys.ttServicesAPIKey24 TomTomSDKOnlineRouting.RoutingOnlineService.routingKey = Keys.ttServicesAPIKey25 }26}2728// MARK: - AppDelegate2930class AppDelegate: NSObject, UIApplicationDelegate {31 func application(32 _ application: UIApplication,33 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil34 )35 -> Bool {36 TomTomServices.register()37 return true38 }39}4041// MARK: - TomTomSDKNavigationUseCaseApp4243@main44struct TomTomSDKNavigationUseCaseApp: App {45 @UIApplicationDelegateAdaptor(AppDelegate.self)46 var appDelegate4748 var body: some Scene {49 WindowGroup {50 MainView()51 }52 }53}5455// MARK: - MainView5657struct MainView: View {58 // MARK: Internal5960 var body: some View {61 MapView(contentInsets: $contentInsets)62 }6364 // MARK: Private6566 @State67 private var contentInsets: EdgeInsets = .init()68}6970// MARK: - MapViewAdd a struct to hold your API key:
1struct Keys {2 static let ttServicesAPIKey = "YOUR_API_KEY"3}
Key storage in the sourcecode is for demo purposes only. Remember to securely store your API keys when creating your app.
These code snippets setup the App
struct and AppDelegate
which registers the TomTom API key with the map display and online routing services. The MapView
is then created in the next section.
Displaying a map
This section explains how to display a map and interact with it. Copy the snippets below into your Xcode project to complete this part of the tutorial.
Create the
MapView
struct:1struct MapView {2 var mapView = TomTomMapView()3 var contentInsets: Binding<EdgeInsets>45 func updateEdgeInsets(context: Context) {6 context.coordinator.setContentInsets(edgeInsets: contentInsets.wrappedValue)7 }8}910// MARK: UIViewRepresentableExend the
MapView
to conform to theUIViewRepresentable
protocol. This allows us to use theTomTomMapView
in SwiftUI:1extension MapView: UIViewRepresentable {2 typealias UIViewType = TomTomSDKMapsDisplay.TomTomMapView34 func makeUIView(context: Context) -> TomTomMapView {5 mapView.delegate = context.coordinator6 mapView.currentLocationButtonVisibilityPolicy = .hiddenWhenCentered7 mapView.compassButtonVisibilityPolicy = .visibleWhenNeeded8 return mapView9 }1011 func updateUIView(_: TomTomMapView, context: Context) {12 updateEdgeInsets(context: context)13 }1415 func makeCoordinator() -> MapCoordinator {16 MapCoordinator(mapView)17 }18}1920// MARK: - MapCoordinatorCreate the
MapCoordinator
, which facilitates communication from the UIView to the SwiftUI environments.1class MapCoordinator: NSObject {2 // MARK: Lifecycle34 init(_ mapView: TomTomMapView) {5 self.mapView = mapView6 }78 // MARK: Internal910 func setContentInsets(edgeInsets: EdgeInsets) {11 mapView.contentInsets = NSDirectionalEdgeInsets(12 top: edgeInsets.top,13 leading: edgeInsets.leading,14 bottom: edgeInsets.bottom,15 trailing: edgeInsets.trailing16 )17 }1819 // MARK: Private2021 private var mapView: TomTomSDKMapsDisplay.TomTomMapView22 private var map: TomTomSDKMapsDisplay.TomTomMap! // Set in onMapReady callback23 private var cameraUpdated = false24 private let routingService = TomTomSDKOnlineRouting.TomTomRoutingService()25 private var navigation: TomTomSDKNavigationEngine.Navigation?26 private let tts = TTS()27}2829// MARK: TomTomSDKMapsDisplay.TomTomMapViewDelegateExtend the
MapCoordinator
to conform to theTomTomMapViewDelegate
protocol by implementing theonMapReady
callback. TheonMapReady
callback notifies theMapCoordinator
that theTomTomMap
is ready to display. TheTomTomMap
instance can be configured in this callback function:1extension MapCoordinator: TomTomSDKMapsDisplay.TomTomMapViewDelegate {2 func tomTomMapView(_ mapView: TomTomMapView, onMapReady map: TomTomMap) {3 // Store the map to be used later4 self.map = map56 // Observe TomTom map actions7 map.delegate = self8 // Observe location engine updates9 map.locationEngine.addObserver(self)10 // Hide the traffic on the map11 map.hideTraffic()12 // Don't display any GPS accuracy information13 map.accuracyIndicatorType = .none14 // Display a chevron at the current location15 map.locationIndicatorType = .navigationChevron(scale: 1)16 // Activate the GPS location engine in TomTomSDK.17 map.activateLocationEngine()18 // Configure the camera to centre on the current location19 map.cameraOptions = defaultCameraOptions20 }21}Next create the camera utility functions. The virtual map is observed through a camera that can be zoomed, panned, rotated, and tilted to provide a compelling 3D navigation experience.
1extension MapCoordinator {2 private var defaultCameraOptions: CameraOptions {3 let defaultLocation = CLLocation(latitude: 0.0, longitude: 0.0)4 return CameraOptions(5 position: defaultLocation.coordinate,6 zoom: 1.0,7 tilt: 0.0,8 rotation: 0.0,9 positionMarkerVerticalOffset: 0.010 )11 }1213 func animateCamera(zoom: Double, position: CLLocationCoordinate2D, animationDurationInSeconds: TimeInterval, onceOnly: Bool) {14 if onceOnly, cameraUpdated {15 return16 }17 cameraUpdated = true18 DispatchQueue.main.async {19 var cameraOptions = self.defaultCameraOptions20 cameraOptions.zoom = zoom21 cameraOptions.position = position22 self.map.animateCamera(cameraOptions, animationDuration: animationDurationInSeconds)23 }24 }2526 func setCamera(trackingMode: TomTomSDKMapsDisplay.CameraTrackingMode) {27 map?.cameraTrackingMode = .followWithHeading28 }29}3031// MARK: TomTomSDKLocation.LocationEngineObserverThe remaining steps in this section ensure the project builds without compiler errors.
Extend
MapCoordinator
to conform toTomTomMapDelegate
and stub the function to handle a long press on the map:1extension MapCoordinator: TomTomSDKMapsDisplay.TomTomMapDelegate {2 func tomTomMap(_: TomTomSDKMapsDisplay.TomTomMap, didLongPressOn coordinate: CLLocationCoordinate2D) {3 // Handle long press4 }5}Extend
MapCoordinator
to conform toLocationEngineObserver
by stubbing the following functions:1extension MapCoordinator: TomTomSDKLocation.LocationEngineObserver {2 func onLocationUpdated(location: GeoLocation) {3 // Handle location updates4 }56 func onHeadingUpdate(newHeading: CLHeading, lastLocation: GeoLocation) {7 // Handle heading updates8 }910 func onAuthorizationStatusChanged(isGranted: Bool) {11 // Handle authorization changes12 }13}Add an empty declaration for the TTS class.
1class TTS {2 // Empty3}
You can now build and run the app on a device or simulator to display a zoomed-out map. You can interact with the map by dragging, pinching or using a two-fingered rotation gesture.
Showing the current location
This section explains how to update the camera position to show the current location, and mark the current location on the map.
Replace the
MapCoordinator
extension that conformed to theLocationEngineObserver
protocol with the following:1extension MapCoordinator: TomTomSDKLocation.LocationEngineObserver {2 func onLocationUpdated(location: GeoLocation) {3 // Zoom and center the camera on the first location received.4 animateCamera(zoom: 9.0, position: location.location.coordinate, animationDurationInSeconds: 1.5, onceOnly: true)5 }67 func onHeadingUpdate(newHeading: CLHeading, lastLocation: GeoLocation) {8 // Handle heading updates9 }1011 func onAuthorizationStatusChanged(isGranted: Bool) {12 // Handle authorization changes13 }14}1516// MARK: TomTomMapDelegateThis extension enables the
MapCoordinator
to observe GPS updates and authorization changes. This means that when the application starts, the camera position and zoom level are updated in theonLocationUpdated
callback function. The user then sees the current location.Update the project’s
info.plist
keys to trigger the app to ask the user for location permission on startup. To do this in Xcode, selectthe project
→the target
→Info
and add strings for the following keys:1NSLocationWhenInUseUsageDescription2NSLocationAlwaysUsageDescription3NSLocationAlwaysAndWhenInUseUsageDescriptionYou can experiment with different ways of showing the current location on the map by changing the
locationIndicatorType
in theonMapReady
callback. Activate the location engine to see the current GPS position on the map:1extension MapCoordinator: TomTomSDKMapsDisplay.TomTomMapViewDelegate {2 func tomTomMapView(_ mapView: TomTomMapView, onMapReady map: TomTomMap) {3 ...45 // Display a chevron at the current location6 map.locationIndicatorType = .navigationChevron(scale: 1)7 // Activate the GPS location engine in TomTomSDK.8 map.activateLocationEngine()9 }10}
After completing these steps, build the app. The camera will zoom in on your current GPS location on startup. The location itself is indicated by the blue chevron. The map will display in portrait and landscape modes as the phone is rotated.
Planning a route
Now we will add the ability to plan a route to a location on the map by responding to the long press gesture.
Update the
MapCoordinator
extension ofTomTomMapDelegate
to plan a route and add it to the map after a long press:1extension MapCoordinator: TomTomMapDelegate {2 func tomTomMap(_: TomTomSDKMapsDisplay.TomTomMap, didLongPressOn coordinate: CLLocationCoordinate2D) {3 Task { @MainActor in4 let routePlan = try await self.planRoute(to: coordinate)5 // First remove any old routes6 self.map?.removeRoutes()7 self.addRouteToMap(route: routePlan.route)8 }9 }10}The call to the async
planRoute
function is wrapped in aTask
so that it can be called from thedidLongPressOn
delegate callback, even though that callback is notasync
.Now create a
MapCoordinator
exension for the route planning functions:1// MARK: Route planning23extension MapCoordinator {4 enum RoutePlanError: Error {5 case unknownStartingLocation6 case unableToPlanRoute(_ description: String = "")7 }89 private func createMapRouteOptions(coordinates: [CLLocationCoordinate2D]) -> TomTomSDKMapsDisplay.RouteOptions {10 var routeOptions = RouteOptions(coordinates: coordinates)11 routeOptions.outlineWidth = 112 routeOptions.routeWidth = 513 routeOptions.color = .activeRoute14 return routeOptions15 }1617 func createRoutingOptions(18 from origin: CLLocationCoordinate2D,19 to destination: CLLocationCoordinate2D20 )21 -> TomTomSDKRouting.RoutingOptions {22 let routingOptionsBuilder = RoutingOptionsBuilder(origin: origin, destination: destination)23 .with(routeType: .fast)24 // For voice announcements:25 .with(instructionsType: .tagged)26 .with(instructionAnnouncementPoints: .all)27 .with(instructionPhonetics: .IPA)28 .includeRoadShieldsInformation()29 .with(instructionRoadShieldReferences: .all)30 .includeSpeedLimits()3132 return routingOptionsBuilder.build()33 }3435 func planRoute(to destination: CLLocationCoordinate2D) async throws -> TomTomSDKNavigationEngine.RoutePlan {36 guard let currentLocation = map?.locationEngine.location?.location.coordinate else {37 throw RoutePlanError.unknownStartingLocation38 }39 return try await planRoute(from: currentLocation, to: destination)40 }4142 func planRoute(43 from origin: CLLocationCoordinate2D,44 to destination: CLLocationCoordinate2D45 ) async throws46 -> TomTomSDKNavigationEngine.RoutePlan {47 let routingOptions = createRoutingOptions(from: origin, to: destination)48 let route = try await planRoute(withRoutingService: routingService, routingOptions: routingOptions)49 return TomTomSDKNavigationEngine.RoutePlan(route: route, routingOptions: routingOptions)50 }5152 func planRoute(53 withRoutingService routingService: TomTomRoutingService,54 routingOptions: RoutingOptions55 ) async throws56 -> TomTomSDKRoute.Route {57 return try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<TomTomSDKRoute.Route, Error>) in58 routingService.planRoute(options: routingOptions) { result in59 switch result {60 case let .failure(error):61 continuation.resume(throwing: error)62 case let .success(response):63 guard let routes = response.routes else {64 continuation.resume(throwing: RoutePlanError.unableToPlanRoute())65 return66 }67 guard let route = routes.first else {68 continuation.resume(throwing: RoutePlanError.unableToPlanRoute())69 return70 }71 continuation.resume(returning: route)72 }73 }74 }75 }76}Create a
MapCoordinator
extension to add the planned route to the map:1extension MapCoordinator {2 func addRouteToMap(route: TomTomSDKRoute.Route) {3 // Create the route options from the route geometry and add it to the map4 let routeOptions = createMapRouteOptions(coordinates: route.geometry)5 _ = try? map?.addRoute(routeOptions)67 // Zoom the map to make the route visible8 map?.zoomToRoutes(padding: 32)9 }10}
You can build the app after completing these steps. The app can then plan a route from your current location to a destination selected with a long press on the map.
Starting navigation
This section explains how to start navigating along the planned route and simulate the journey.
Create a
MapCoordinator
extension that contains the functions to start and configure navigation:1// MARK: Navigation23extension MapCoordinator {4 func createSimulatedLocationEngine(route: TomTomSDKRoute.Route) -> LocationEngine {5 let simulatedLocationEngine = SimulatedLocationEngine(delay: 0.2)6 simulatedLocationEngine.updateCoordinates(route.geometry, interpolate: true)7 return simulatedLocationEngine8 }910 func createNavigation(locationEngine: LocationEngine) -> TomTomSDKNavigationEngine.Navigation {11 let navigationConfiguration = NavigationConfigurationBuilder(12 navigationKey: Keys.ttServicesAPIKey,13 locationEngine: locationEngine,14 routingService: routingService15 )16 .with(routeReplanningMode: .automatic)17 .build()18 let navigation = Navigation(configuration: navigationConfiguration)19 // Set the TomTomSDKNavigationEngine.TomTomNavigationDelegate to receive navigation callbacks about the journey such as route instructions20 navigation.delegate = self21 return navigation22 }2324 func startNavigation(25 navigation: TomTomSDKNavigationEngine.Navigation,26 locationEngine: TomTomSDKLocation.LocationEngine,27 routePlan: TomTomSDKNavigationEngine.RoutePlan28 ) {29 // Set the navigation location engine30 navigation.stop()31 navigation.locationEngine = locationEngine3233 navigation.start(routePlan: routePlan) { error in34 print("Error starting navigation: \(error)")35 }3637 // The map matched location engine snaps to the route38 let locationEngine = navigation.mapMatchedLocationEngine39 map?.setCustomLocationEngine(locationEngine)4041 // Set the camera tracking mode to follow the current position42 setCamera(trackingMode: .followWithHeading)43 }44}4546// MARK: TomTomSDKNavigationEngine.TomTomNavigationDelegateNext update the
didLongPressOn
callback function fromTomTomMapDelegate
to plan the route and start navigating:1extension MapCoordinator: TomTomMapDelegate {2 func tomTomMap(_: TomTomSDKMapsDisplay.TomTomMap, didLongPressOn coordinate: CLLocationCoordinate2D) {3 Task { @MainActor in4 do {5 // Plan the route and add it to the map6 let routePlan = try await planRoute(to: coordinate)7 // First remove any old routes8 map?.removeRoutes()9 addRouteToMap(route: routePlan.route)1011 // Sart navigation after a short delay so that we can clearly see the transition to the driving view12 DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in13 guard let self = self else {14 return15 }1617 // Use real location updates18 // let locationEngine = self.map.locationEngine1920 // Use simulated location updates21 let locationEngine = self.createSimulatedLocationEngine(route: routePlan.route)2223 let navigation = self.navigation ?? self.createNavigation(locationEngine: locationEngine)24 self.startNavigation(25 navigation: navigation,26 locationEngine: locationEngine,27 routePlan: routePlan28 )29 self.navigation = navigation30 // Start location updates31 locationEngine.start()32 }33 } catch {34 print("Error when planning a route: \(error)")35 }36 }37 }3839 func tomTomMap(_: TomTomSDKMapsDisplay.TomTomMap, gesture: TomTomSDKMapsDisplay.Gesture, didSendEvent _: GestureEvent) {40 // Handle gesture41 }4243 func tomTomMap(_: TomTomSDKMapsDisplay.TomTomMap, didChangeCameraTrackingMode mode: CameraTrackingMode) {44 // Handle camera tracking mode change45 }4647 func tomTomMapDidTapOnRecenterButton(_ map: TomTomSDKMapsDisplay.TomTomMap) {48 // Handle recenter map49 }50}The
didLongPressOn
callback function starts navigation by callingstartNavigation
with the desired location engine. Experiment by switching between real and simulated GPS location engines as shown in the code snippet above.Extend
MapCoordinator
to conform to theTomTomNavigationDelegate
protocol. Thedelegate
was set in thecreateNavigation
function.1extension MapCoordinator: TomTomSDKNavigationEngine.TomTomNavigationDelegate {2 func tomTomNavigation(3 _ navigation: TomTomSDKNavigationEngine.Navigation,4 didReplanRoute replannedRoute: TomTomSDKRoute.Route,5 reason: TomTomSDKNavigationEngine.RouteReplanningReason6 ) {7 print("replanned route")8 }910 func tomTomNavigation(11 _ navigation: TomTomSDKNavigationEngine.Navigation,12 didUpdateProgress: TomTomSDKNavigationEngine.RouteProgress13 ) {14 print("distance along route = \(didUpdateProgress.distanceAlongRouteInMeters)m")15 }1617 func tomTomNavigation(18 _ navigation: TomTomSDKNavigationEngine.Navigation,19 didGenerateAnnouncement announcement: TomTomSDKNavigationEngine.GuidanceAnnouncement20 ) {21 tts.play(announcement: announcement)22 }23}2425// MARK: - TTSNow stub the play function in the
TTS
class:1class TTS {2 func play(announcement: TomTomSDKNavigationEngine.GuidanceAnnouncement) {3 // Do nothing4 }5}
You can build the app after completing these steps. Do a long press on the map to plan a route to that location and start the navigation simulation.
Voice guidance
This section explains how to add voice instructions to the app.
Implement the
TTS
class as follows:1class TTS {2 // MARK: Lifecycle34 init(languageCode: String) {5 let ttsEngine = SystemTextToSpeechEngine(language: languageCode)6 self.ttsProvider = TomTomSDKTextToSpeech.makeTextToSpeech(ttsEngine: ttsEngine)7 }89 convenience init() {10 let languageCode = Locale.preferredLanguages.first ?? Locale.current.languageCode ?? "en-GB"11 self.init(languageCode: languageCode)12 }1314 // MARK: Internal1516 func play(announcement: TomTomSDKNavigationEngine.GuidanceAnnouncement) {17 guard let message = announcement.verbalMessage else {18 return19 }20 var phonetics: [TomTomSDKTextToSpeechEngine.PhoneticTranscription] = if let streetPhonetics = parseStreetPhonetics(phonetics: announcement.verbalMessagePhonetics) {21 phonetics.append(streetPhonetics)22 }23 if let signpostPhonetics = parseSignpostPhonetics(phonetics: announcement.verbalMessagePhonetics) {24 phonetics.append(signpostPhonetics)25 }26 if let roadNumberPhonetics = parseRoadNumberPhonetics(phonetics: announcement.verbalMessagePhonetics) {27 phonetics.append(roadNumberPhonetics)28 }29 let ttsMessage = TTSMessage.tagged(message: message, phonetics: phonetics)30 let priority = TTSMessagePriority(timeout: messageTimeout)31 ttsProvider.play(message: ttsMessage, priority: priority)32 }3334 // MARK: Private3536 private let messageTimeout: TimeInterval = 10.0 // seconds37 private let ttsProvider: TomTomSDKTextToSpeech.TextToSpeechProtocol3839 private func parseStreetPhonetics(phonetics: TomTomSDKRoute.Phonetics?) -> TomTomSDKTextToSpeechEngine40 .PhoneticTranscription? {41 guard let street = phonetics?.street, let languageCode = phonetics?.streetLanguageCode else {42 return nil43 }44 return PhoneticTranscription(45 transcriptions: [street],46 languageCodes: [languageCode],47 tag: DefaultTags.streetName,48 alphabet: DefaultPhoneticAlphabets.ipa49 )50 }5152 private func parseSignpostPhonetics(phonetics: TomTomSDKRoute.Phonetics?) -> TomTomSDKTextToSpeechEngine53 .PhoneticTranscription? {54 guard let signpost = phonetics?.signpostText, let languageCode = phonetics?.signpostTextLanguageCode else {55 return nil56 }57 return PhoneticTranscription(58 transcriptions: [signpost],59 languageCodes: [languageCode],60 tag: DefaultTags.signpost,61 alphabet: DefaultPhoneticAlphabets.ipa62 )63 }6465 private func parseRoadNumberPhonetics(phonetics: TomTomSDKRoute.Phonetics?) -> TomTomSDKTextToSpeechEngine66 .PhoneticTranscription? {67 guard let roadNumbers = phonetics?.roadNumbers, let languageCodes = phonetics?.roadNumberLanguageCodes else {68 return nil69 }70 return PhoneticTranscription(71 transcriptions: roadNumbers,72 languageCodes: languageCodes,73 tag: DefaultTags.streetName,74 alphabet: DefaultPhoneticAlphabets.ipa75 )76 }77}The
TTS
class configures a text to speech provider using theSystemTextToSpeechEngine
. Phonetic data is parsed from theGuidanceAnnouncement
object and played back by the TTS provider. TheTextToSpeechEngine
protocol also declares functions for stopping playback, changing volume, and changing language.
You can build the app after completing these steps. You will be able to hear voice guidance during the navigation simulation.
Next steps
The TomTom Navigation SDK allows you to customize the appearance of the map and its overlays, use your own Navigation UI components, or provide a custom implementation of certain navigation behaviors.