Quickstart
Offline functionality for the Maps SDK and Navigation SDK for Android is only available upon request. Contact us to get started.
The Navigation SDK offers a complete navigation experience, including the ability to work with offline maps. Offline maps allow users to search for destinations, plan routes, and navigate even without an internet connection.
The offline maps are divided into map regions. A map region can be any geographical area: a city such as Amsterdam, an area inside a country such as North Holland, a country such as The Netherlands, or a region such as Benelux.
You can choose to update or install any map region so that the data is available to other components of the SDK for offline use. When used offline, the Navigation SDK only uses data from the map regions that are installed on the device.
In this guide, we will walk you through the process of setting up and using offline maps in your application.
Prerequisites
Before proceeding, ensure that you do the following:
-
Gain 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 the generated token and use it to specify your credentials in your project
gradle.properties
file:- Replace
user_name_placeholder
with the login username or email you use for repositories.tomtom.com. - Replace
identity_token_placeholder
with the generated identity token.
repositoryUsername=user_name_placeholderrepositoryIdentityToken=identity_token_placeholder - Replace
-
Project configuration: Add a maven block to your
settings.gradle
file to specify the credentials and the URI for repositories.tomtom.com.1dependencyResolutionManagement {2 repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)3 repositories {4 google()5 mavenCentral()6 maven {7 credentials {8 username = repositoryUsername9 password = repositoryIdentityToken10 }11 url = uri("https://repositories.tomtom.com/artifactory/maven")12 }13 }14} -
Offline setup package: This package should contain a map, a keystore, a map access license token, and an API key for map updates.
-
Project setup: Configure your project according to the instructions provided in the Project setup guide.
Adding dependencies
Add the following module dependency in the build.gradle.kts
of your application module and synchronize the project.
implementation("com.tomtom.sdk.datamanagement:nds-store:1.20.0")implementation("com.tomtom.sdk.datamanagement:nds-store-updater:1.20.0")
Storing the offline map on a device
The offline setup package includes a map and a keystore. To ensure proper access, store these files on the device in a way that allows the application to access them. You can choose to embed the files as part of the application’s assets or save them in a cloud space and retrieve them during the initial launch of the application.
If opting for external storage, you should be aware of the following limitations:
- Permissions: Adjust your application to request the necessary permissions for accessing external storage. For detailed instructions, refer to the section on Permissions and access to external storage.
- Filesystem in Userspace (FUSE): Note that Android 11 or higher defaults to using Filesystem in Userspace (FUSE) for SD cards. FUSE can significantly affect performance when dealing with large files, impacting SDK components’ performance.
It is strongly recommended to consult the Android Developer Guide on Mitigating FUSE Performance. This guide provides a comprehensive understanding and potential workarounds for performance issues related to FUSE.
Loading the offline map
The offline map must be compliant with the Navigation Data Standard version 2.4.6. Other Navigation Data Standard versions are not supported.
To utilize the offline map, you need to instantiate the NdsStore
object, which allows you to load offline map data. Other SDK components can then use it for their features.
For map management functionalities, such as enabling automatic map updates, installing or removing map regions, and querying map structures, you will need NdsStoreUpdater
.
Follow these steps to construct the NdsStore
and NdsStoreUpdater
objects:
- Define the necessary file paths and directories:
1// Assume the map and the keystore files are stored on the app-specific storage2val rootDir = context.filesDir3val mapDir = rootDir.resolve("map")4val keystorePath = rootDir.resolve("keystore.sqlite")5val updateDir = rootDir.resolve("update") // NdsStoreUpdater will create this directory6val persistentDir = rootDir.resolve("persistent") // NdsStoreUpdater will create this directory
- Create the
NdsStoreConfiguration
object:1val defaultNdsStoreConfig =2 NdsStoreConfiguration(3 ndsStorePath = mapDir,4 keystorePath = keystorePath,5 accessPermit = NdsStoreAccessPermit.MapLicense("YOUR_MAP_LICENSE"),6 ) - Create the
NdsStore
object and handle any potential failures:1ndsStore =2 NdsStore.create(context = context, configuration = defaultNdsStoreConfig).fold(3 { it },4 {5 // Error handling - Your code goes here6 throw IllegalStateException(it.message)7 },8 ) - Set up the
NdsStoreUpdaterConfiguration
:1val defaultUpdateConfig =2 NdsStoreUpdaterConfiguration(3 updateStoragePath = updateDir,4 persistentStoragePath = persistentDir,5 updateServerApiKey = TOMTOM_API_KEY,6 ) - Create the
NdsStoreUpdater
object and handle any potential failures:1ndsStoreUpdater =2 NdsStoreUpdater.create(3 context = context,4 ndsStore = ndsStore,5 configuration = defaultUpdateConfig,6 ).fold(7 { it },8 {9 // Error handling - Your code goes here10 throw IllegalStateException(it.toString())11 },12 )
To access a specific offline map, create only one instance of NdsStore and NdsStoreUpdater. Creating multiple instances for the same map can lead to unexpected behavior.
Downloading map contents around the specified location
The offline map included in the setup package contains only metadata and does not include pre-installed map regions. Therefore, it is necessary to download and install map regions before utilizing search, display, routing, or navigation functionalities.
To enable automatic map updates around the specified location, follow these steps:
- Create the
NdsStoreUpdater
object with anNdsStoreUpdaterConfiguration
that is set up to enable the updates:1ndsStoreUpdater =2 NdsStoreUpdater.create(3 context = context,4 ndsStore = ndsStore,5 configuration =6 defaultUpdateConfig.copy(7 automaticUpdates =8 defaultAutomaticNdsStoreUpdaterConfiguration.copy(9 relevantRegions = RelevantRegions(),10 ),11 ),12 ).fold(13 { it },14 {15 // Error handling - Your code goes here16 throw IllegalStateException(it.toString())17 },18 ) - Add an
RegionGraphListener
to monitor the success events of map updates, and then enable map updates:1private var rootNodes = listOf<RegionGraphNode>()2private val nodeStates = mutableMapOf<RegionGraphNodeId, RegionGraphNodeState>()3private val regionGraphListener =4 object : RegionGraphListener {5 override fun onRegionGraphChanged(6 regionGraphResult: Result<RegionGraph, MapUpdateError>,7 mapRegionStates: Map<RegionGraphNodeId, RegionGraphNodeState>,8 ) {9 regionGraphResult10 .ifSuccess {11 // Your code goes here12 // For example, you can save the region graph and the states13 rootNodes = it.roots14 nodeStates.clear()15 nodeStates.putAll(mapRegionStates)16 }17 .ifFailure {18 // Your code goes here19 Log.e(TAG, "Can't get RegionGraph: $it")20 }21 }2223 override fun onMapRegionStatesChanged(mapRegionStates: Map<RegionGraphNodeId, RegionGraphNodeState>) {24 // Your code goes here25 // for example, update the current states26 nodeStates.putAll(mapRegionStates)27 }28 } - Update the position by passing the location to the
NdsStore
.val amsterdam = GeoPoint(52.377956, 4.897070)ndsStoreUpdater.updatePosition(amsterdam)
The NdsStoreUpdater
will download the relevant map regions around the specified location in the background. Upon successful map update, you will receive a notification from RegionGraphListener
. The more details about RegionGraphListener
can be found in Manual Map Management
Utilizing the NdsStore
Now that the NdsStore
is created and map contents are successfully downloaded, you can use it with other SDK components. For example, you can create a route planner:
val routePlanner = OfflineRoutePlanner.create(ndsStore)
With the route planner, you can plan routes by providing the desired itinerary:
1val amsterdam = GeoPoint(52.377956, 4.897070)2val rotterdam = GeoPoint(51.926517, 4.462456)3val routePlanningOptions = RoutePlanningOptions(itinerary = Itinerary(amsterdam, rotterdam))4val result = routePlanner.planRoute(routePlanningOptions)5if (result.isSuccess()) {6 // Success - Your code goes here7 val route = result.value().routes.first()8} else {9 // Error handling - Your code goes here10 val error = result.failure()11}
Next steps
You have successfully set up and utilized offline maps with the Navigation SDK. To further enhance your offline map implementation, consider exploring the following topics:
- Offline Map Setup: Learn more about advanced configuration options and customization possibilities for offline maps.
- Manual Map Management: Explore how to manually manage map regions, including downloading, updating, and removing specific regions.
- Build an offline navigation app: Learn how to implement a basic offline navigation application.
By diving deeper into these areas, you can unlock the full potential of offline maps in your application.