Download maps for offline use
An offline pack holds the resources needed to show a region without a network:
map tiles, the style, and other assets. The OfflineManager
creates, tracks, and deletes packs.
Get the manager from the map runtime. A composable, a view model, a background
worker, or main can hold and use it:
val offlineManager = DefaultMapRuntime.instance.offlineManagerDownload a region
Section titled “Download a region”A pack is defined by a style URL, a bounding box, and a zoom range.
OfflineManager.create registers the pack in a paused state; call
OfflineManager.resume to start the download:
val offlineState by offlineManager.state.collectAsState()Button( enabled = offlineState is OfflineManagerState.Ready, onClick = { scope.launch { val pack = offlineManager.create( definition = OfflinePackDefinition.TilePyramid( styleUrl = "https://tiles.openfreemap.org/styles/liberty", bounds = BoundingBox(west = -123.0, south = 47.0, east = -122.0, north = 48.0), pixelRatio = pixelRatio, minZoom = 10, maxZoom = 14, ), metadata = "Seattle".encodeToByteArray(), ) offlineManager.resume(pack) } },) { Text("Download Seattle")}The library does not interpret the metadata bytes. Use them to identify the
pack later, for example with a display name.
OfflinePackDefinition.Shape downloads the region that covers a
GeoJSON geometry instead of a bounding box.
Track download progress
Section titled “Track download progress”OfflineManager.state and OfflinePack.downloadProgress
are StateFlows. A composition collects them with collectAsState and
recomposes as the download proceeds:
val packs = (offlineState as? OfflineManagerState.Ready)?.packs.orEmpty()when (val state = offlineState) { OfflineManagerState.Loading -> Text("Loading offline packs…") is OfflineManagerState.Failed -> Text(state.cause.message ?: "Could not load offline packs") is OfflineManagerState.Ready -> Unit}for (pack in packs) { key(pack) { val metadata by pack.metadata.collectAsState() val progress by pack.downloadProgress.collectAsState() val name = metadata?.decodeToString() ?: "Unnamed" when (val current = progress) { is DownloadProgress.Healthy -> Text("$name: ${current.completedResourceCount} resources, ${current.status}") is DownloadProgress.Error -> Text("$name: ${current.message}") is DownloadProgress.TileLimitExceeded -> Text("$name: tile limit ${current.limit}") is DownloadProgress.Unknown -> Text("$name: waiting for status") } }}A background worker can collect downloadProgress until the pack reports
DownloadStatus.Complete. The manager starts in OfflineManagerState.Loading
while it lists stored packs. OfflineManagerState.Ready includes the packs from
earlier sessions; OfflineManagerState.Failed reports initialization errors.
Operations suspend until initialization completes.
pause and resume switch a pack between the Paused and Downloading
states. OfflineManager.invalidate re-checks a pack’s tiles
against the server and updates the ones that changed.
Delete a pack
Section titled “Delete a pack”OfflineManager.delete unregisters the pack and frees the
resources that no remaining pack requires:
for (pack in packs) { key(pack) { val metadata by pack.metadata.collectAsState() Button(onClick = { scope.launch { offlineManager.delete(pack) } }) { Text("Delete ${metadata?.decodeToString()}") } }}Once a pack is downloaded, the map uses its resources automatically when the device has no network. No map configuration is required.