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 !
Finally I was able to display the ZXY tiles according to the MapBox "file://" protocol. Thanks to @typebrook and @githengi. I describ my problem here in detail.
The first issue that caused the problem was android permission. Considerations for display ZXY tiles by MapBox SDK:
First we define related permission in the AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
It should be noted that you may need to check required permission before adding the layer. For more information on that refer to the Request App Permissions. Then use the following code:
I used the Global Mapper software to produce "png" tiles. You should download ZXY tiles sample that i used .
Although the problem of rendering ZXY tiles from external storage was solved for me, it would be great if a compressed file (Like .mbtiles format) could be used in this protocol.
In this regard, MBTilesServer.kt developed by @typebrook and another solution for reading external mbtiles developed by @githengi. For more detail in the @githengi solution see kujaku/mbtiole package.
I tried to import kujaku/mbtiole package in my project and use it. It seems that Tile Server works properly, but the requests are made by Android policy canceled. Myy error log display:
cleartext communication to localhost not permitted by network security policy
I googled the error log and add "android:usesCleartextTraffic="true"" to my project but I failed. I dot have any idea, but it may be because of the versions of Mapbox or Android SDK(i used updated versions).
I think I talked a lot! So if we can create a simple app that display a 'Mbtiles file', it will help many people.
My knowledge is not advanced in Android programming but I will do my best to help.