Skip to main content

Offline

If your user base spends most of their time off the grid, use the Mapbox Maps SDK's offline features to download and store selected regions for use when there is a loss of connectivity. The maps they download will be fully functional and include the styles, tiles, and other resources you specify.

An offline map requires two main components:

  1. Style data, which is organized into style packs. Use the Offline Manager API to manage style packs.
  2. Map data, which is organized into preassembled tile packs. Use the tile store to manage tile packs.

These are a few key terms and concepts you may need to reference when working with offline maps:

  • Offline Manager: The Offline Manager API provides a configuration interface and entrypoint for offline map functionality. It is used to manage style packs and to produce tileset descriptors that can be used with a tile store.
  • Tileset descriptor: A tileset descriptor contains metadata about the tilesets, zoom ranges, and pixel ratio that cached tile packs should include. You can create tileset descriptors with the Offline Manager. Each time you create a tile pack, you will provide both a tileset descriptor and a tile region before tile data can be fetched for offline use.
  • Tile Region: A tile region is a geographic area for which offline data is needed. Tile regions are used by tile stores to fetch and manage tile packs necessary to provide offline support in that area. To create a tile region, a developer must specify a geometry describing each region's boundaries, source tileset(s), and zoom range(s).
  • Tile Pack: Tile packs are binary files made up of a parent tile and its descendant tiles covering a specific range of zoom levels and over a predefined geographic area. Because they have less per-tile and per-connection overhead more efficient to transfer over the network and store on the file system than individual tiles. Tile packs only store tiles. The Offline Manager API handles metadata and descriptors related to tilesets.
  • Tile Store: The tile store manages retrieving and organizing tile packs. The Maps SDK uses the tile store for the offline data such as tile regions or style pack resources. The tile store does not share tiles with the disk cache (see note on disk cache below). Although the Offline Manager manages style packs and handles creating tileset descriptors, it is the job of the tile store to manage tile regions.
  • Style pack: A style pack contains a map style and the non-tile resources it depends upon, including loaded sources, fonts, sprites, and 3d models. Collectively, these resources are used to transform map data stored in tiles into a rendered map with a particular look and feel. Style packs are identified by their style URL.
book
Disk cache
When a user loads and interacts with a map on their device, any visible tiles and style resources (style JSON, fonts, sprites, etc.) are placed in the device's disk cache, which is located in the maps data directory defined in the MapboxMapsOptions#dataPath. The disk cache observes when these resources are used and makes intelligent guesses about which resources may be needed again. When a user revisits a place on the map, it will load more quickly if the associated resources are still present in the disk cache, because the device will not have to request those resources from the server to render the map.Resources are not permanently stored in the disk cache. There are no guarantees about how long these resources will be cached, but the least-recently used resources are normally removed to make room for newer resources.

Limits

The cumulative amount of unique maps tile packs used in the offline regions cannot be greater than 750. The SDK will not do tile region loading if it would lead to exceeding the tile pack limit.

Our terms of service do not allow developers or end users to redistribute offline maps downloaded from Mapbox servers. Users of the SDK must retrieve Mapbox data intended for offline use from Mapbox servers--the data may not be preloaded, bundled or otherwise redistributed.

Specifying the style and areas that will be used offline

To render a complete map in an offline environment, the device needs to fetch two main components: a style and the required map tiles, each of which needs to be configured ahead of time.

Define a style pack

To render a map offline, the SDK must be able to fetch the non-tile resources that the map requires. This includes loaded sources, fonts, styles and sprites. The SDK calculates which resources it needs based on the StylePackLoadOptions you specify and pass to the Offline Manager API.

val stylePackLoadOptions = StylePackLoadOptions.Builder()
.glyphsRasterizationMode(GlyphsRasterizationMode.IDEOGRAPHS_RASTERIZED_LOCALLY)
.metadata(Value(STYLE_PACK_METADATA))
.build()

Define a tileset descriptor and tile region

The tileset descriptor associates tile data (stored in a tile pack) to a given style (stored in a style pack). Use the tileset descriptor to define a tileset's zoom ranges and pixel ratio.

The tile region is a geographic region and its metadata. It is used to calculate which tile packs will be necessary to provide offline functionality in that region.

val offlineManager: OfflineManager = OfflineManager()

val tilesetDescriptor = offlineManager.createTilesetDescriptor(
TilesetDescriptorOptions.Builder()
.styleURI(Style.OUTDOORS)
.minZoom(0)
.maxZoom(16)
.build()
)
val tileRegionLoadOptions = TileRegionLoadOptions.Builder()
.geometry(TOKYO)
.descriptors(listOf(tilesetDescriptor))
.metadata(Value(TILE_REGION_METADATA))
.acceptExpired(false)
.networkRestriction(NetworkRestriction.NONE)
.build()

Metadata

You may provide arbitrary metadata for both style packs and tile regions. You may want to provide metadata to distinguish the various regions your users download from one another or for other record-keeping requirements within your app. This data will be associated with the style packs and regions that the system fetches and stores locally. While optional, providing a metadata object with at least a region name is encouraged. Besides a region name, you can store any arbitrary serializable information you'd like as long as it can be wrapped into a Value class. For example, you might wish to store the record ID of a travel itinerary that a user has created in another part of your app, and for which the offline region is being retrieved, to link the two together. The contents of the metadata you specify will only be available inside your app and will not affect your tile region download.

Add metadata to the style pack with StylePackLoadOptions.

val stylePackLoadOptions = StylePackLoadOptions.Builder()
...
.metadata(Value(STYLE_PACK_METADATA))
.build()

Add metadata to the tile region with TileRegionLoadOptions.

val tileRegionLoadOptions = TileRegionLoadOptions.Builder()
...
.metadata(Value(TILE_REGION_METADATA))
.build()

Working with downloads

Once the above steps are complete, the system has the information necessary to know what to resources must be downloaded. The next step is to start downloads for each of your style packs and tile packs.

Download a style pack

Now that the StylePackLoadOptions has been created, you can use the OfflineManager to create a style pack asynchronously by calling loadStylePack. loadStylePack returns a Cancelable object, allowing you to abort the download by calling cancel().

To initialize the download, pass in the StylePackLoadOptions you created in both the Define a style pack and Metadata sections.

This will provide you with two callbacks:

  1. StylePackLoadProgressCallback tracks the progress of the download.
  2. StylePackCallback tracks the completion of the download or any errors that occur. It returns a StylePack object when the download completes successfully, which you can use to check the downloaded style package, including its expiration date.
val stylePackCancelable = offlineManager.loadStylePack(
Style.OUTDOORS,
// Build Style pack load options
stylePackLoadOptions,
{ progress ->
// Handle the download progress
},
{ expected ->
if (expected.isValue) {
expected.value?.let { stylePack ->
// Style pack download finished successfully
}
}
expected.error?.let {
// Handle errors that occurred during the style pack download.
}
}
)
// Cancel the download if needed
stylePackCancelable.cancel()

Download a tile region

In the previous step, you used the Offline Manager API to download a style pack. You will use the tile store in a similar way to download any tile packs required to render your map offline.

To create an asynchronous tile region download, call the tile store's loadTileRegion method and pass in the TileRegionLoadOptions you created in the Define a tileset descriptor and tile region and Metadata sections. loadTileRegion will return a Cancelable object, which may be used to abort the download.

loadTileRegion will provide you with two callbacks:

  1. TileRegionLoadProgressCallback tracks the download progress.
  2. TileRegionCallback tracks the completion of the download or any errors that occur. It provides a TileRegion object when the download completes successfully, which you can use to check the downloaded tile region, including its expiration date.
val tileStore = TileStore.create()
val tileRegionCancelable = tileStore.loadTileRegion(
TILE_REGION_ID,
TileRegionLoadOptions.Builder()
.geometry(TOKYO)
.descriptors(listOf(tilesetDescriptor))
.metadata(Value(TILE_REGION_METADATA))
.acceptExpired(false)
.networkRestriction(NetworkRestriction.NONE)
.build(),
{ progress ->
// Handle the download progress
}
) { expected ->
if (expected.isValue) {
// Tile region download finishes successfully
expected.value?.let {
}
}
expected.error?.let {
// Handle errors that occurred during the tile region download.
}
}

// Cancel the download if needed
tileRegionCancelable.cancel()

Manage offline data

Once a download has completed, you may want to give your users the option to view and manage their downloads in one place. The Offline Manager API and tile store each provide methods for listing and managing offline data.

List offline style packs and regions

Call OfflineManager#getAllStylePacks to get a list of available style packs. This will return an object (Expected) that includes a list of available style packs or an error.

// Get a list of style packs that are currently available.
offlineManager.getAllStylePacks { expected ->
if (expected.isValue) {
expected.value?.let { stylePackList ->
Log.d("Existing style packs: $stylePackList")
}
}
expected.error?.let { stylePackError ->
Log.e("StylePackError: $stylePackError")
}
}

Similarly, use TileStore#getAllTileRegions to get a list of available tile regions. This will return an object (Expected) that includes a list of available tile regions or an error.

 // Get a list of tile regions that are currently available.
tileStore.getAllTileRegions { expected ->
if (expected.isValue) {
expected.value?.let { tileRegionList ->
Log.d("Existing tile regions: $tileRegionList")
}
}
expected.error?.let { tileRegionError ->
Log.e("TileRegionError: $tileRegionError")
}
}

Update a style pack

To maintain the integrity of a style package, the map style that belongs to an offline pack will not be automatically updated if a user returns to an area with network services and views the map while connected. This includes loaded sources, glyphs, sprites and 3D models.

You can manually refresh style packs using OfflineManager#loadStylePack, passing it the same StyleUri and an empty StylePackLoadOptions (note that if the acceptExpired flag is true, the existing outdated resources will not be refreshed). During the refresh, any missing resources will be loaded and expired resources will be updated.

Update a region

Downloaded tile regions can be refreshed using the same TileStore#loadTileRegion call you made when you initialized your download. Provide the same tile region ID (TILE_REGION_ID in the download initialization example above) and an empty TileRegionLoadOptions (note that if the acceptExpired flag is true the existing outdated resources will not be refreshed). During the refresh, any missing resources will be loaded and any expired resources will be updated.

Normally, the map does not load new tile packs from the network, unless MapboxMapsOptions#TileStoreUsageMode is READ_AND_UPDATE. If MapboxMapsOptions#TileStoreUsageMode is READ_AND_UPDATE, the map will replace the outdated visible tile packs with fresh ones for all the tile regions that refer to these tile packs.

Delete style packs and regions

To remove offline data from the database, you must first receive the list of tile regions as explained in the List offline style packs and regions section. Once this list has been retrieved it may be used to select the style pack and/or tile regions to be deleted.

Delete a style pack using the OfflineManager#removeStylePack API and the style's URI.

offlineManager.removeStylePack(StyleUri)

Note this may not immediately delete the downloaded style pack. Instead, it will mark the resources as not being a part of an offline style pack and they will be removed from the disk cache during its normal cleanup process.

You can delete a tile region with TileStore#removeTileRegion.

tileStore.removeTileRegion(TILE_REGION_ID)

Note that this may not immediately delete the downloaded tile packs. Instead, it will mark the tileset as not being a part of an offline tile region and they will be removed from the disk cache during its normal cleanup process.

You can fully remove tiles that have been downloaded by setting the disk quota to zero. This will make sure tile regions are fully removed. See the section entitled Tile store disk quota.

Understanding and configuring offline behavior

Understanding the default behavior and options of the Maps SDK's offline functionality can allow you to optimize your app's offline functionality and manage it more flexibly.

Each Map instance stores files for both the disk cache and tile store in a default location (normally, inside the application cache folder). To override the default, you can provide a custom data path for the disk cache and a tile store instance. There is only ever one tile store for each unique file path.

The Offline Manager can be configured using MapboxMapsOptions. You can completely disable the tile store by setting MapboxMapsOptions#TileStoreUsageMode to DISABLED. In this case, a tile store will not be created and tile region functionality will not be available.

By default, a tile store is read-only and the Maps SDK only interacts with it to check for tiles it needs. If the necessary tile is not in the tile store, the SDK will request the individual tile and store it in the disk cache instead of the tile store. By default, the SDK will not fetch tile packs in scenarios like this, where a tile is not available locally and must be retrieved.

You can enable implicit tile pack loading by setting the MapboxMapsOptions#TileStoreUsageMode resource option to READ_AND_UPDATE. When set to READ_AND_UPDATE, the map engine will use the tile store for loading tile packs rather then load tiles individually. Only tile packs will be used. This option can be useful if the map trajectory is predefined and the user cannot pan freely (For example: navigation use cases). In these circumstances, it is more efficient to use tile packs for all map data loading instead of allowing the map to request arbitrary tiles.

Tile store disk quota

By default, there is no limit to the size of a tile store. A quota can be configured with the TileStoreOptions.DISK_QUOTA option.

Tile store will refuse to store new data on disk if it would cause the quota to be exceeded. To make room for new content, tiles packs with the nearest expiration dates that aren't shared by another tile region will be removed before the quota is reached. By default, this happens when there are 50 Mb left.

book
Disk quota before Mapbox Maps SDK v11.2.0

Before Mapbox Maps SDK 11.2.0, removal of tile packs was triggered only after the quota was exceeded. Since tile packs that are part of a tile region wouldn't be removed, this could cause the tile store to grow permanently over the specified quota.

For instance, if you set TileStoreOptions.DISK_QUOTA to 500 Mb then nothing will be removed until the tile store size reaches 450 Mb. After that, tile store will start evicting tile packs with the nearest expiration date which are not part of any region to try to keep the size under 450 Mb. In case all tile packs belong to some region and nothing can be evicted, tile store may keep growing and use the entire quota of 500 Mb. After that no new tile packs can be added to the tile store and some regions would need to be removed or TileStoreOptions.DISK_QUOTA would need to be increased.

// Set a quota of 100 Mb. Tile store will try to keep it's size around 50Mb and will not allow to save
// new tile packs when tile store size is over 100Mb
tileStore.setOption(TileStoreOptions.DISK_QUOTA, Value(100 * 1024 * 1024))

Tile count granularity

The tile store loads and stores tiles in tile packs. Each tile pack has a pre-defined zoom range and contains all child tiles within that range. The tile leveling scheme for a tileset is determined in the TileJSON. The default tile pack zoom ranges are:

  • Global coverage: 0 - 5
  • Regional information: 6 - 10
  • Local information: 11 - 14
  • Streets detail: 15 - 16

When specifying minimum and maximum zoom levels as part of the TilesetDescriptorOptions, the actual zoom levels of the retrieved data will be determined by these ranges. For example, if you set minZoom to 8 and maxZoom to 15, the downloaded tiles will include zoom levels ranging from 6 to 16.

Supported tiled sources

Tile regions support only the tiled sources whose tile endpoint URLs correspond to the Mapbox Vector/Raster tile v4 URL schema or Mapbox Raster DEM tile v1 URL schema. Your tiled source probably uses the v4 URL schema unless it is more than a few years old.

Potential risks on updating the offline style

Changing the used style in offline scenarios should be executed with carefully to make sure that the existing loaded style packages and tile regions continue to function correctly after the update.

Modifications to the style layers that interact with the current style sources are typically safe. Note that modifications to the style sources entail adjustments to the tiles in use, which could potentially cause already loaded tile regions to become incompatible with the updated style.

Composited sources

While source compositing helps to load the map faster during online usage, it introduces potential risks for offline scenarios.

In general, we recommend to disable source compositing when creating a styles for the offline usage to avoid known limitations listed below.

Rigid tile scheme in legacy Offline

For the legacy offline system (the deprecated OfflineRegionManager API), any modification of the bundled source URL makes existing offline regions incompatible. This occurs because tiles are stored using their URLs as resource keys. When source compositing is enabled, the tiles URL structure looks something like scheme://source_a,source_b. So any updated URL, such as scheme://source_a,source_b,source_c or even scheme://source_b,source_a, is treated as an entirely different tile that does not apply for the style.

The new offline system always stores the tile packages independently for every tileset and thus it is not susceptible to the described issue.

Composited tile components do not overscale

When two or more components with different maximum zoom levels are used in a composited source, there is a situation where, if the camera is displaying a zoom level higher than the maximum zoom of one of the source components, data from that particular source component will not be rendered.

This limitation arises because, for offline usage, source compositing is performed on the client side (from the stored tile packs data), and the implementation is constrained in comparison to server-side source compositing logic.

Style pack transition to tile store in v11

In v10, style packs were stored in the disk cache that is employed during normal online map use. In v11, style packs resources are stored in the tile store along with the tile packs, thus providing more holistic approach for storing of the offline resources. All existing style packs are migrated to the tile store on the update operation. This transition is performed transparently and requires no additional actions from the client.

For an existing style pack, the transition occurs after the successful completion of the OfflineManager#loadStylePack call for the package. When all the resources are successfully loaded to the tile store the previous style package is removed from the disk cache.

Be aware that the resources are re-downloaded from the server during the transition.

If, for any reason, you wish to retain the style pack in the disk cache after the transition, specify the "keep-legacy-style-pack" extra load option.

val stylePackLoadOptions = StylePackLoadOptions.Builder()
...
.extraOptions(Value.fromJson("""{keep-legacy-style-pack": true}""")?.value)
.build()
Was this page helpful?