Join us online - 19th of November
Save your spot
For AI agents: a documentation index is available at /llms.txt. Markdown versions of all pages are available by appending .md to any URL.

Getting Started with Offline Pack API - Kotlin SDK

The MapTiler SDK for Kotlin provides a powerful Offline Pack API that enables downloading map regions for offline usage. This is a critical feature for navigation, hiking apps, or any scenario where internet access is unreliable.

Before you begin, ensure you have followed the Android SDK Getting Started guide to configure your project and set your API key.

Installation

Add the MapTiler SDK dependency to your build.gradle.kts file:


dependencies {
    implementation("com.maptiler.sdk:maptiler-sdk-kotlin:2.0.0")
}

View Installation Instructions

Basic usage

Implementing offline maps involves defining a region, creating an offline pack via the manager, and tracking the download progress.

Step 1: Define the region

Specify the geometry (area), zoom range, and the MapTiler style you want to make available offline.


import com.maptiler.maptilersdk.offline.*
import com.maptiler.maptilersdk.map.style.MTMapReferenceStyle

// Define a bounding box (e.g., Zurich)
val bbox = MTBoundingBox(
    minLon = 8.52, minLat = 47.36,
    maxLon = 8.56, maxLat = 47.39
)

// Create the definition
val definition = MTOfflineRegionDefinition(
    geometry = MTOfflineRegionGeometry.BoundingBox(bbox),
    minZoom = 1,
    maxZoom = 12,
    referenceStyle = MTMapReferenceStyle.STREETS
)

Step 2: Create the offline pack

Use the MTOfflineManager to initialize a new pack on the device.


// In a coroutine scope
val pack = MTOfflineManager.createPack(context, definition)

Step 3: Observe download progress

Set up observers in a coroutine scope.


launch {
  pack.progressFlow.collect { progress ->
    val percent = (progress.percentage * 100).toInt()
    println("Progress: $percent% (${progress.downloadedResources}/${progress.totalResources} resources)")
              
    // You can also access:
    // progress.downloadSpeed (resources/sec)
    // progress.estimatedTimeRemaining (seconds)
  }
}

// Observe state changes (DOWNLOADING, COMPLETED, FAILED, etc.)
launch {
  pack.stateFlow.collect { state ->
    when (state) {
      MTOfflinePackState.DOWNLOADING -> println("Download started...")
      MTOfflinePackState.COMPLETED -> println("Download finished successfully!")
      MTOfflinePackState.FAILED -> println("Download failed.")
      else -> println("Current state: ${state.name}")
    }
  }
}

Step 4: Start the download

Trigger the download process. Using useBackground = true will offload the work to Android’s WorkManager.


pack.download(useBackground = true)

Step 5: Display the pack on the map

Load a completed pack with loadOfflinePack. Do not wait for onMapViewInitialized before calling it, because when offline it fires only after a pack is loaded.


controller.loadOfflinePack(pack, limitToRegion = true)

To return to the online map, call controller.unloadOfflinePack().

Features

Flexible Geometries

Offline regions aren’t limited to rectangles. You can define regions based on:

  • Bounding Box: A simple rectangular area.
  • Route: Download tiles along a GeoJSON route with a specific buffer.
  • Polygon: Download tiles within a custom polygon boundary.

Background Downloading

With useBackground = true, the SDK uses WorkManager to handle downloads. It automatically manages battery optimization, network changes, and device reboots.

Pack Management

Easily manage your stored maps:

  • List Packs: await MTOfflinePack.packs()
  • Resume/Pause: await pack.resume() or await pack.pause()
  • Remove: await pack.remove()

Permissions

Offline packs are served to the map by a small local server on 127.0.0.1. The SDK already ships a network security config that allows cleartext traffic to 127.0.0.1 and localhost. No extra setup is needed.

Only if your app defines its own android:networkSecurityConfig, the manifest merger will report a conflict. In that case, add these entries to your existing config file and override the SDK’s attribute:


<?xml version="1.0" encoding="utf-8"?>
  <network-security-config>
     <domain-config cleartextTrafficPermitted="true">
         <domain includeSubdomains="false">127.0.0.1</domain>
         <domain includeSubdomains="false">localhost</domain>
     </domain-config>
 </network-security-config>

Reference it in your AndroidManifest.xml:


<application
    android:networkSecurityConfig="@xml/your_network_security_config"
    tools:replace="android:networkSecurityConfig"
... >

Android ignores android:usesCleartextTraffic="true" when a network security config is present.

What to Expect

Storage: Map tiles are stored in a dedicated folder. A typical city-sized area at zoom level 12 might take 50-100MB depending on the style complexity.

Expiration: Packs have an expiration date (default is 30 days). You can use pack.refresh() to update the resources and reset the timer.

Network: The SDK automatically handles intermittent connectivity, pausing and resuming downloads as the network becomes available.

Learn more

To learn about more advanced functionalities of the SDK, refer to the API Reference.

Check out our SDK Kotlin Examples. In addition to the documentation examples take a look at the plug and play examples provided in the SDK GitHub repository, as well as pre-made demo app: maptiler-sdk-kotlin/Examples

Was this helpful?