Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
How to make MBTiles valid on Mapbox Android SDK #mbtiles #android #mapbox

MBTilesSource.kt + MbtilesServer.kt

What it does?

It enables a MapboxMap (from Mapbox Android SDK) to use MBTiles as Source.

Inspired from similar Swift approach in iOS SDK, made by @namannik.

How it works?

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.

Installation

  • Add MBTilesSource.kt and MBTilesServer.kt (from this gist) into your Android project.

Usage

Prepare network configuration

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.

  1. Add network configuration into AndroidManifest.xml
    android:networkSecurityConfig="@xml/network_security_config" >
  2. 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>

Create a MBTilesSource to read your MBTiles file

// 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")

Remove a source from MBTilesServer

 mbSource.deactivate()

Work with Mapbox Style

// 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(vector)

How it looks like?

I created this for my app, Five More Minutes. This demo use vector MBTiles and style from OpenMapTiles.

Alternatives

  • 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

  • If it won't bother you to store tiles with folders, you can use asset:// and file:// protocol with source. See related thread in StackOverflow here.

CHANGELOG

  • 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
package com.example.sample.offline
import android.util.Log
import java.io.BufferedReader
import java.io.ByteArrayOutputStream
import java.io.FileNotFoundException
import java.io.PrintStream
import java.net.ServerSocket
import java.net.Socket
import kotlin.math.pow
/*
* Localhost tile server with MBTilesSource
*/
object MBTilesServer : Runnable {
const val port = 8888
private val serverSocket: ServerSocket = ServerSocket(port)
var isRunning = false
val sources: MutableMap<String, MBTilesSource> = mutableMapOf()
fun start() {
isRunning = true
Thread(this).start()
}
fun stop() {
isRunning = false
serverSocket.close()
}
override fun run() {
try {
while (isRunning) {
serverSocket.accept().use { socket ->
Log.d(javaClass.simpleName, "Handling request")
handle(socket)
Log.d(javaClass.simpleName, "Request handled")
}
}
} catch (e: Exception) {
Log.d(
javaClass.simpleName,
e.localizedMessage ?: "Exception while running MBTilesServer"
)
} finally {
Log.d(javaClass.simpleName, "request handled")
}
}
@Throws
private fun handle(socket: Socket) {
val reader: BufferedReader = socket.getInputStream().reader().buffered()
// Output stream that we send the response to
val output = PrintStream(socket.getOutputStream())
try {
var route: String? = null
// Read HTTP headers and parse out the route.
do {
val line = reader.readLine() ?: ""
if (line.startsWith("GET")) {
// the format for route should be {source}/{z}/{x}/{y}
route = line.substringAfter("GET /").substringBefore(".")
break
}
} while (line.isNotEmpty())
// the source which this request target to
val source = sources[route?.substringBefore("/")] ?: return
// Prepare the content to send.
if (null == route) {
writeServerError(output)
return
}
val bytes = loadContent(source, route) ?: run {
writeServerError(output)
return
}
// Send out the content.
with(output) {
println("HTTP/1.0 200 OK")
println("Content-Type: " + detectMimeType(source.format))
println("Content-Length: " + bytes.size)
if (source.isVector) println("Content-Encoding: gzip")
println()
write(bytes)
flush()
}
} finally {
reader.close()
output.close()
}
}
@Throws
private fun loadContent(source: MBTilesSource, route: String): ByteArray? = try {
val (z, x, y) = route.split("/").subList(1, 4).map { it.toInt() }
source.getTile(z, x, (2.0.pow(z)).toInt() - 1 - y)
} catch (e: FileNotFoundException) {
e.printStackTrace()
null
}
private fun writeServerError(output: PrintStream) {
output.println("HTTP/1.0 500 Internal Server Error")
output.flush()
}
private fun detectMimeType(format: String): String? = when (format) {
"jpg" -> "image/jpeg"
"png" -> "image/png"
"mvt" -> "application/x-protobuf"
"pbf" -> "application/x-protobuf"
else -> "application/octet-stream"
}
}
package com.example.sample.offline
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import com.mapbox.mapboxsdk.style.sources.RasterSource
import com.mapbox.mapboxsdk.style.sources.Source
import com.mapbox.mapboxsdk.style.sources.TileSet
import com.mapbox.mapboxsdk.style.sources.VectorSource
import java.io.File
import java.io.FileOutputStream
import kotlin.properties.Delegates
/*
* Mapbox Source backend by localhost tile server
*/
sealed class MBTilesSourceException : Exception() {
class CouldNotReadFileException : MBTilesSourceException()
class UnsupportedFormatException : MBTilesSourceException()
}
class MBTilesSource(filePath: String, sourceId: String? = null) {
val id = sourceId ?: filePath.substringAfterLast("/").substringBefore(".")
val url get() = "http://localhost:${MBTilesServer.port}/$id/{z}/{x}/{y}.$format"
private val db: SQLiteDatabase = try {
SQLiteDatabase.openOrCreateDatabase(filePath, null)
} catch (e: RuntimeException) {
throw MBTilesSourceException.CouldNotReadFileException()
}
val instance: Source by lazy {
if (isVector) VectorSource(id, TileSet(null, url))
else RasterSource(id, TileSet(null, url))
}
var isVector by Delegates.notNull<Boolean>()
lateinit var format: String
// var tileSize: Int? = null
// var layersJson: String? = ""
// var attributions: String? = ""
// var minZoom: Float? = null
// var maxZoom: Float? = null
// var bounds: LatLngBounds? = null
init {
try {
format = db.query(
"metadata", null, "name = ?",
arrayOf("format"), null, null, null
).use { cursor ->
cursor.moveToFirst()
val index = cursor.getColumnIndex("value")
cursor.getString(index)
}
isVector = when (format) {
in validVectorFormats -> true
in validRasterFormats -> false
else -> throw MBTilesSourceException.UnsupportedFormatException()
}
} catch (error: MBTilesSourceException) {
print(error.localizedMessage)
}
}
fun getTile(z: Int, x: Int, y: Int): ByteArray? {
return db.query(
"tiles", null, "zoom_level = ? AND tile_column = ? AND tile_row = ?",
arrayOf("$z", "$x", "$y"), null, null, null
).use { cursor ->
if (cursor.count == 0) return null
cursor.moveToFirst()
val index = cursor.getColumnIndex("tile_data")
cursor.getBlob(index)
}
}
fun activate() = with(MBTilesServer) {
sources[id] = this@MBTilesSource
if (!isRunning) start()
}
fun deactivate() = with(MBTilesServer) {
sources.remove(id)
if (isRunning && sources.isEmpty()) stop()
}
companion object {
val validRasterFormats = listOf("jpg", "png")
val validVectorFormats = listOf("pbf", "mvt")
fun readAsset(context: Context, asset: String): String =
context.assets.open(asset).use { inputStream ->
val path = context.getDatabasePath(asset).path
val outputFile = File(path)
FileOutputStream(outputFile).use { outputStream ->
inputStream.copyTo(outputStream)
outputStream.flush()
}
return path
}
}
}
@grzesiek2010

This comment has been minimized.

Copy link

@grzesiek2010 grzesiek2010 commented Apr 28, 2020

Hi @typebrook
The limitation you mentioned which in fact is a big limitation might be fixed if you call Mapbox.setConnected(true); after initializing Mapbox.

@typebrook

This comment has been minimized.

Copy link
Owner Author

@typebrook typebrook commented Apr 29, 2020

@grzesiek2010
Many thanks! Never expect somebody would answer this.

@JeongJun-Lee

This comment has been minimized.

Copy link

@JeongJun-Lee JeongJun-Lee commented May 23, 2020

Hello, thank you for your great gist. I have a question. Do you think I can make a hybrid app to interact between leaflet.js on web layer and this mapview on the native layer?

@typebrook

This comment has been minimized.

Copy link
Owner Author

@typebrook typebrook commented May 25, 2020

You mean create a native APP with webview, and use leaflet with tiles served on localhost? I think it would be fine.

@JeongJun-Lee

This comment has been minimized.

Copy link

@JeongJun-Lee JeongJun-Lee commented May 25, 2020

By this gist guideline, I tried a very basic code to load mbtiles gotten from OpenMapTiles at offline. But it doesn't work. There is no error to load mbtiles from local, to assign MBTilesSource and to start MBTilServer. I share my repo. Could give me more guideline for solving it? Thanks.

@typebrook

This comment has been minimized.

Copy link
Owner Author

@typebrook typebrook commented May 25, 2020

@JeongJun-Lee
Really surprised, it works out of the box even 2 years passed.

I just changed some of your code, and style-bright.json works great on Seoul, this means mbtileserver is running. See snapshot and diffs below:
alt text
Screenshot from 2020-05-25 18-39-07
Screenshot from 2020-05-25 18-39-23

Of course the Mapbox token and OpenMapTiles key above are both fake, replace them with your own.
Feel free to ask me if you stuck on something

@JeongJun-Lee

This comment has been minimized.

Copy link

@JeongJun-Lee JeongJun-Lee commented May 25, 2020

Great!!! It works. Thanks a lot!!! For fully offline support, maybe it seems that both the sprite and glyphs in style.json should be also in local. Do you have any idea for that?

@typebrook

This comment has been minimized.

Copy link
Owner Author

@typebrook typebrook commented May 25, 2020

I think Mapbox-gl-native already supports asset protocol (AssetFileSource with asset://) from 6.5.0. So it would be fine to put glyphs and sprite into asset.

For example:
https://github.com/mapbox/mapbox-gl-native/tree/5438af2ad6853a4fa0d55459d436f9f3321ccd63/platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts

If you don't care about MBTiles format, you can even put tiles into asset directly. see https://stackoverflow.com/a/40518151/7051075

@JeongJun-Lee

This comment has been minimized.

Copy link

@JeongJun-Lee JeongJun-Lee commented May 25, 2020

By your guide, I succeed in adding local glyphs to style.json and also I found another open source glyphs. But I didn't find the open source sprites yet. By the way, I bet here all comments we mentioned would be a good start for a offline vector map!

@typebrook

This comment has been minimized.

Copy link
Owner Author

@typebrook typebrook commented May 25, 2020

But I didn't find the open source sprites

Sprite is just a collection of images with json file as metadata.
Mapbox Maki editor is CC0 licensed and good enough for everything. I thinks most of the sprites in OpenMapTiles styles are made by it (For example: https://github.com/openmaptiles/osm-liberty-gl-style#icon-design)

I bet here all comments we mentioned would be a good start for a offline vector map

Thanks for your feedback! Though I am not working on FiveMoreMinutes now, but still keep contributing on the stacks of tile generation.
If you are interested, try tilemaker to make your own tiles/MBTiles with OpenMapTiles schema.

@Cacaonut

This comment has been minimized.

Copy link

@Cacaonut Cacaonut commented Jun 6, 2020

I had some hard time getting this to work, so I just wanted to mention my problem here, so it might help others in future:

Mapbox connects to the local tile server using HTTP, but

Starting with Android 9 (API level 28), cleartext support is disabled by default.
See Android Developers

Therefore you have to allow HTTP traffic to localhost. There are several ways achieve this (see here), the cleanest one by declaring a network security config like this:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config xmlns:android="http://schemas.android.com/apk/res/android">
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="false">localhost</domain>
    </domain-config>
</network-security-config>

For more information on that refer to the Android Developers documentation.

Btw, @typebrook, thanks for your awesome work.

@typebrook

This comment has been minimized.

Copy link
Owner Author

@typebrook typebrook commented Jun 8, 2020

@Cacaonut

I never test it on Android 9 or above, really grateful for your information!
Have a good day!

@mortezaomidi

This comment has been minimized.

Copy link

@mortezaomidi mortezaomidi commented Jul 31, 2020

@typebrook, thanks for your awesome work.
I want to show some BaseMap Layer (or Background ==> zxy, or mbtile) from external storage by using the mapbox sdk for android. In my scenario user should be able to choose a directory (containing zxy tiles or maybe my Mbtiles) by an Intent and then data added to style as a layer (maybe you suggest a better scenario).

I will try to convert your classes to Java and announce the result.

@typebrook

This comment has been minimized.

Copy link
Owner Author

@typebrook typebrook commented Aug 1, 2020

@mortezaomidi
Thank you for sharing this. For Android external storage, it seems like file protocol (file://path/to/tile) is needed. Since Mapbox doesn't mention anything in their docs, I am also very curious about this approach.

I am a little busy on this weekend, so I will start to test some cases after next Monday. Will get back to you if anything is confirmed.

@mortezaomidi

This comment has been minimized.

Copy link

@mortezaomidi mortezaomidi commented Aug 2, 2020

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:

               `RasterSource rasterSource = new RasterSource("testTileSource", 
                  new TileSet("tileset",
                        "file://" + Environment.getExternalStorageDirectory() + "/tiles/{z}/{x}/{y}.png")
                );
                mapboxMap.getStyle().addSource(rasterSource);
                RasterLayer rasterLayer = new RasterLayer("testTileLayer",
                        "testTileSource");
                mapboxMap.getStyle().addLayer(rasterLayer);`

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.

@typebrook

This comment has been minimized.

Copy link
Owner Author

@typebrook typebrook commented Aug 2, 2020

@mortezaomidi
Did you check the comment from @Cacaonut?

@mortezaomidi

This comment has been minimized.

Copy link

@mortezaomidi mortezaomidi commented Aug 3, 2020

@mortezaomidi
Did you check the comment from @Cacaonut?

Yes. but the mentioned problem by @Cacaonut occurs to me when using the kujaku/mbtiole package . I create a repository here and I tested it. I would be thankful if someone could help me to display mbtiles from external storage (Specifically a Java solution).
I could not convert these two files (MBTilesSource.kt + MbtilesServer.kt) to the sample java app.

@typebrook

This comment has been minimized.

Copy link
Owner Author

@typebrook typebrook commented Aug 3, 2020

I would be thankful if someone could help me to display mbtiles from external storage (Specifically a Java solution).
I could not convert these two files (MBTilesSource.kt + MbtilesServer.kt) to the sample java app.

@mortezaomidi
Nah, I won't make another redundant files for Java version. Use Kotlin code doesn't mean you need to refactor your whole project.
Thanks to JetBrains, we can call Kotlin module without any issue in Java file. All you need to do is just add plugin for Kotlin, which has fully support by Google, and just add MBTilesSource.kt + MbtilesServer.kt.

I made a PR for things mentioned above at mortezaomidi/mbtiles#1. Since I don't have your sample mbtiles, you still need some efforts to make it works.

Anyway, your case reminds me that Mapbox already changed API. So instead of MapboxMap, Style is responsible for addSource() and addLayer() now. I'll update README later. Have a good day!

@mortezaomidi

This comment has been minimized.

Copy link

@mortezaomidi mortezaomidi commented Aug 3, 2020

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:

               `RasterSource rasterSource = new RasterSource("testTileSource", 
                  new TileSet("tileset",
                        "file://" + Environment.getExternalStorageDirectory() + "/tiles/{z}/{x}/{y}.png")
                );
                mapboxMap.getStyle().addSource(rasterSource);
                RasterLayer rasterLayer = new RasterLayer("testTileLayer",
                        "testTileSource");
                mapboxMap.getStyle().addLayer(rasterLayer);`

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.

I created a small project to help other people for displaying offline zxy tiles from external storage in mapbox SDK. In this project, I used PermissionsDispatcher to handle runtime permissions. I hope this can solve someone's problem.

1
2
3
4

@typebrook

This comment has been minimized.

Copy link
Owner Author

@typebrook typebrook commented Aug 4, 2020

@mortezaomidi

I created a small project to help other people for displaying offline zxy tiles from external storage in mapbox SDK. In this project, I used PermissionsDispatcher to handle runtime permissions. I hope this can solve someone's problem.

That's great! So I guess you already solve your issue in mapbox-gl-native-android?

Does the mbtiles package in onaio/kujaku works in your case? Before your post, I didn't know there is such a package for MBTiles in Mapbox SDK.

@mortezaomidi

This comment has been minimized.

Copy link

@mortezaomidi mortezaomidi commented Aug 4, 2020

I would be thankful if someone could help me to display mbtiles from external storage (Specifically a Java solution).
I could not convert these two files (MBTilesSource.kt + MbtilesServer.kt) to the sample java app.

@mortezaomidi
Nah, I won't make another redundant files for Java version. Use Kotlin code doesn't mean you need to refactor your whole project.
Thanks to JetBrains, we can call Kotlin module without any issue in Java file. All you need to do is just add plugin for Kotlin, which has fully support by Google, and just add MBTilesSource.kt + MbtilesServer.kt.

I made a PR for things mentioned above at mortezaomidi/mbtiles#1. Since I don't have your sample mbtiles, you still need some efforts to make it works.

Anyway, your case reminds me that Mapbox already changed API. So instead of MapboxMap, Style is responsible for addSource() and addLayer() now. I'll update README later. Have a good day!

@typebrook
Thanks for your PR. I was able to successfully display a raster PNG.

for me this line of code:

private val db: SQLiteDatabase = try { SQLiteDatabase.openOrCreateDatabase(filePath, null) } catch (e: RuntimeException) { throw MBTilesSourceError.CouldNotReadFileError() }

raised error and i chanced it to :

private val db: SQLiteDatabase = try { SQLiteDatabase.openDatabase(filePath, null, SQLiteDatabase.OPEN_READONLY) } catch (e: RuntimeException) { throw MBTilesSourceError.CouldNotReadFileError() }

Therefore, I confirm that by using the MBTilesSource.kt we can render mbtiles in newest MapBox SDK (mapbox-android-sdk:9.3.0).

1

New changes have been made to the mortezaomidi/mbtiles repo and you can see it here

Regarding vector tiles format, I think the project works well, only the definition of tile set needs to be defined. I will try to examine this issue as well.

@mortezaomidi

This comment has been minimized.

Copy link

@mortezaomidi mortezaomidi commented Aug 4, 2020

@mortezaomidi

I created a small project to help other people for displaying offline zxy tiles from external storage in mapbox SDK. In this project, I used PermissionsDispatcher to handle runtime permissions. I hope this can solve someone's problem.

That's great! So I guess you already solve your issue in mapbox-gl-native-android?

Does the mbtiles package in onaio/kujaku works in your case? Before your post, I don't know there is such a package for MBTiles in Mapbox SDK.

Thanks for pointing me to the issue. I closed mapbox/mapbox-gl-native-android#342 (comment).

For me the mbtiles package in onaio/kujaku not works but i think the library works well with a little effort! Maybe @Cacaonut comment was the problem.

@mortezaomidi

This comment has been minimized.

Copy link

@mortezaomidi mortezaomidi commented Aug 4, 2020

A good news! This time I was able to show offline vector mbtiles by using the grate @typebrook MBTilesServer.kt.
download a sample OSM vector mbtile here and then follow this repository. For managing cartographic representation i use this. You can change it based on your preferences.

1

I consider it necessary to appreciate @typebrook this would not have been possible for me without her guidance..

@utya

This comment has been minimized.

Copy link

@utya utya commented Aug 25, 2020

can i use sprite and glyphs localy?

@typebrook

This comment has been minimized.

Copy link
Owner Author

@typebrook typebrook commented Aug 25, 2020

@utya

can i use sprite and glyphs localy?

Yes, both of them supports asset:// and file:// protocol, see my comment at top.

@utya

This comment has been minimized.

Copy link

@utya utya commented Aug 25, 2020

@typebrook
now i means instead of

"sprite": "https://rawgit.com/lukasmartinelli/osm-liberty/gh-pages/sprites/osm-liberty",
"glyphs": "https://orangemug.github.io/font-glyphs/glyphs/{fontstack}/{range}.pbf",

use somethitng like this

"sprite": "local_path",
"glyphs": "local_path"

i need offline solution,

@typebrook

This comment has been minimized.

Copy link
Owner Author

@typebrook typebrook commented Aug 26, 2020

@utya
That is exactly what I mentioned, check how Mapbox applys those protocol in the test APP:
https://github.com/mapbox/mapbox-gl-native/blob/5438af2/platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/streets.json#L100

@utya

This comment has been minimized.

Copy link

@utya utya commented Sep 2, 2020

maybe anybody generate mbtiles from geojson? i cant' make mbtiles from geojson and work with this mbtileserver. Works only mbtiles from openmaptiles

@typebrook

This comment has been minimized.

Copy link
Owner Author

@typebrook typebrook commented Sep 2, 2020

maybe anybody generate mbtiles from geojson?

@utya
You should check tippecanoe

@utya

This comment has been minimized.

Copy link

@utya utya commented Sep 2, 2020

i genearated using this sourcs. but unfortunate. Could you send working sample created by tipprcanoe?

@typebrook

This comment has been minimized.

Copy link
Owner Author

@typebrook typebrook commented Sep 3, 2020

@utya
Well, generating MBTIiles is off topic in this gist. We should stop talking here.
If you have any trouble when creating MBTiles with tippecanoe, you'd better check trouble-shooting in mapbox website, or just create a new issue in tippecanoe repo. If you still have some issues unsolved but not related to this gist, a new stackoverflow post should be a good idea (Or just send me a mail)

@utya

This comment has been minimized.

Copy link

@utya utya commented Sep 3, 2020

@typebrook
thanks and sorry

@TroyStopera

This comment has been minimized.

Copy link

@TroyStopera TroyStopera commented Jan 17, 2021

I have a use case where users should be able to copy over their own mbtiles files and I'd like to use that as a source. I have it working for raster tiles, but vector (pbf specifically, but haven't tried mvt) are not rendering. I feel that it has something to do with layers. I've tried reading the json field from the metadata table, and using the layer IDs from there and creating LineLayer('id from json', source.id) and adding that to my Style. Still not working. Was hoping to get some tips or ideas. Thanks!

@typebrook

This comment has been minimized.

Copy link
Owner Author

@typebrook typebrook commented Jan 26, 2021

Hi ! @TroyStopera
Sorry for the late reply. In your reply, I think you are confused with "source layer"(The data in Vector Tiles) and "Mapbox layer" (The collection of features rendered in map).

You can define "Mapbox layer" id by yourself, it's not related to anything in metadata of a MBTiles. I think the json you mentioned is related about the list of "source layers", but it is not required in every MBTIles. And if a "Mapbox layer" use a specific "source layer", you need to use source-layer to do configuration, see Mapbox documentation

If you still have any problem, welcome to reply here.

@TroyStopera

This comment has been minimized.

Copy link

@TroyStopera TroyStopera commented Jan 28, 2021

@typebrook thank you! I think I was confusing the two concepts. I'm still a bit confused on how to render these user-provided, vector-based mbtiles files though.

How can I find what source layers I need to add? Does the mbtiles file tell me? Also, how do I know what type of layer (line, circle, fill, etc...) to create and add to the style?

I'm understanding that I need to add these source layers to the style. It is really just figuring out what layers the mbtiles file has. I know that vector mbtiles files have a json metadata field that looks something like:

"vector_layers":[ { "maxzoom":14, "fields":{ "class":"String" }, "minzoom":0, "id":"water", "description":"" } ]

Which does tell me the layer id, but not what type of layer to use...
I've tried adding a LineLayer for each layer in the vector_layers array and setting the source-layer to match the id from the json but it doesn't seem to work.

@typebrook

This comment has been minimized.

Copy link
Owner Author

@typebrook typebrook commented Feb 2, 2021

How can I find what source layers I need to add? Does the mbtiles file tell me?

  1. Ask the provider of this MBTiles. For example, openmaptiles list their schema at https://openmaptiles.org/schema/
  2. According to MBTiles spec, the layers are described as json object only after 1.3 (as you mentioned

Also, how do I know what type of layer (line, circle, fill, etc...) to create and add to the style?

It depends on your usecase. For example, a source layer with geometry=LineString can be used with SymbolLayer or LineLayer.
If you are not familiar with these Mapbox styling spec, better to use Maputnik or Mapbox studio to do some practice/design.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment