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.


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.
  • 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 = repositoryUsername
    9 password = repositoryIdentityToken
    10 }
    11 url = uri("https://repositories.tomtom.com/artifactory/maven")
    12 }
    13 }
  • 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.


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:

  1. Define the necessary file paths and directories:
    1// Assume the map and the keystore files are stored on the app-specific storage
    2val rootDir = context.filesDir
    3val mapDir = rootDir.resolve("map")
    4val keystorePath = rootDir.resolve("keystore.sqlite")
    5val updateDir = rootDir.resolve("update") // NdsStoreUpdater will create this directory
    6val persistentDir = rootDir.resolve("persistent") // NdsStoreUpdater will create this directory
  2. Create the NdsStoreConfiguration object:
    1val defaultNdsStoreConfig =
    2 NdsStoreConfiguration(
    3 ndsStorePath = mapDir,
    4 keystorePath = keystorePath,
    5 accessPermit = NdsStoreAccessPermit.MapLicense("YOUR_MAP_LICENSE"),
    6 )
  3. 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 here
    6 throw IllegalStateException(it.message)
    7 },
    8 )
  4. Set up the NdsStoreUpdaterConfiguration:
    1val defaultUpdateConfig =
    2 NdsStoreUpdaterConfiguration(
    3 updateStoragePath = updateDir,
    4 persistentStoragePath = persistentDir,
    5 updateServerApiKey = TOMTOM_API_KEY,
    6 )
  5. 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 here
    10 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:

  1. Create the NdsStoreUpdater object with an NdsStoreUpdaterConfiguration 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 here
    16 throw IllegalStateException(it.toString())
    17 },
    18 )
  2. 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 regionGraphResult
    10 .ifSuccess {
    11 // Your code goes here
    12 // For example, you can save the region graph and the states
    13 rootNodes = it.roots
    14 nodeStates.clear()
    15 nodeStates.putAll(mapRegionStates)
    16 }
    17 .ifFailure {
    18 // Your code goes here
    19 Log.e(TAG, "Can't get RegionGraph: $it")
    20 }
    21 }
    23 override fun onMapRegionStatesChanged(mapRegionStates: Map<RegionGraphNodeId, RegionGraphNodeState>) {
    24 // Your code goes here
    25 // for example, update the current states
    26 nodeStates.putAll(mapRegionStates)
    27 }
    28 }
  3. Update the position by passing the location to the NdsStore.
    val amsterdam = GeoPoint(52.377956, 4.897070)

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 here
7 val route = result.value().routes.first()
8} else {
9 // Error handling - Your code goes here
10 val error = result.failure()

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.