It enables a MapboxMap
(from Mapbox Android SDK) to use MBTiles as Source
.
Inspired from similar Swift approach in iOS SDK, made by @namannik.
In you APP, when a MBTilesSource
instance activates, it starts a localhost MBTilesServer
and works like a common Mapbox Raster/Vector Source.
MBTilesServer
is a Singleton. It can hosts multiple MBTilesSource
. The URL for each MBTilesSource
is http://localhost:8888/[Source ID]/{z}/{x}/{y}.[jpg|png|pbf|mvt]
Since MBTilesSource
only works as common Mapbox Raster/Vector Source, you always need to add layer or set style for MapboxMap by yourself. Mapbox Style is a bit more complex. If your MBTiles contains vector tile (.mvt), make sure your specify correct value for source-layer
. See spec here.
Also, you may check an example by MapTiler, an OSM vector tiles provider.
- Add
MBTilesSource.kt
andMBTilesServer.kt
(from this gist) into your Android project.
To make sure MBTilesServer
works without network connection above Android 9 (API level 28), you have to allow HTTP traffic to localhost.
For more information, see Android Developers.
- Add network configuration into
AndroidManifest.xml
android:networkSecurityConfig="@xml/network_security_config" >
- A resource file named in
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config cleartextTrafficPermitted="true"> <domain includeSubdomains="false">localhost</domain> </domain-config> </network-security-config>
// Connect to localhost even when device is not connected to internet
Mapbox.setConnected(true)
// Create MBTilesSource
val path = "/path/to/source.mbtiles" // file path
val sourceId = "source1" // used as Mapbox Source ID
val mbSource = try {
MBTilesSource(path, sourceId).apply { activate() }
} catch (e: MBTilesSourceException.CouldNotReadFileException){
// Deal with error if fail to read MBTiles
}
Now, a XYZ Tile Service is working on http://localhost:8888/source1/{z}/{x}/{y}.[mvt|pbf|jpg|png]
.
The file extension of each tile is judged by the format in MBTiles. (Defined in table metadata
, only mvt, pbf, jpg, png are allowed)
Also, if your MBTiles is at asset folder, you may use companion object in MBTilesSource
to copy it into internal storage, and get the path directly.
val path = MBTilesSource.readAsset(context, "FILENAME.mbtiles")
mbSource.deactivate()
// In callback of Style.OnStyleLoaded
style.addSource(mbSource.instance)
// If mbSource contains raster tiles
val rasterLayer = RasterLayer("raster_layer_id", mbSource.id)
style.addLayer(rasterLayer)
// If mbSource contains vector tiles
val vectorLayer = LineLayer("vector_layer_id", mbSource.id)
style.addLayer(vectorLayer)
I created this for my app, Five More Minutes. This demo use vector MBTiles and style from OpenMapTiles.
-
If you want to create an APP with map which really reads MBTiles directly, consider use Tangram SDK instead of Mapbox SDK. It natively support use a MBTiles as source offline, see Documentation here.
Do not challenge why Mapbox doesn't support a format they created :D
-
Or, use Maplibre-gl-native, a mapbox-gl-native fork which embraces open source!
-
If it won't bother you to store tiles with folders, you can use
asset://
andfile://
protocol with source. See related thread in StackOverflow here.
- 2021-01-26
- Add Alternatives section
- 2020-11-25
- Add network configuration for newer Android version, thanks @Cacaonut !
- Remove Anko from dependencies
- Code refactor
- Exmaple refactor for latest Mapbox API
- 2020-05-26
- Fix connection issue about localhost, thanks @grzesiek2010 !
It depends on your usecase. For example, a source layer with
geometry=LineString
can be used withSymbolLayer
orLineLayer
.If you are not familiar with these Mapbox styling spec, better to use Maputnik or Mapbox studio to do some practice/design.