You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

MapLibre Android(Kotlin)加载并渲染MBTiles离线地图的实现方案咨询

MapLibre Android(Kotlin)加载并渲染MBTiles离线地图的实现方案咨询

我来帮你梳理下MapLibre Android加载MBTiles的正确姿势——刚好我之前做过类似的离线地图需求,给你一步步拆解问题和实现代码:


一、核心结论:MapLibre Android 完全支持MBTiles

不能直接通过file://路径作为Source的URL传入!因为MBTiles是封装在SQLite数据库里的瓦片集合,不是直接的瓦片文件目录,必须用MapLibre官方提供的TileStore组件来加载,而不是直接读文件路径。


二、具体实现代码(Kotlin)

先讲前置准备,再分「栅格MBTiles」和「矢量MBTiles」两种情况给出可运行代码:

前置准备:处理MBTiles文件的存储

如果你把MBTiles放在assets目录,必须在build.gradle里配置禁止压缩该文件(SQLite文件压缩后会损坏):

// Groovy 版 build.gradle
android {
    aaptOptions {
        noCompress "mbtiles"
    }
}

// Kotlin 版 build.gradle.kts
android {
    aaptOptions {
        noCompress("mbtiles")
    }
}

另外,assets里的文件是只读的,MapLibre的TileStore需要可访问的文件路径,推荐先把assets里的MBTiles复制到App私有目录(filesDir):

private fun copyMbtilesToPrivateDir(context: Context, assetFileName: String): File {
    val destFile = File(context.filesDir, assetFileName)
    if (destFile.exists()) return destFile

    // 从Assets复制到私有目录
    context.assets.open(assetFileName).use { inputStream ->
        FileOutputStream(destFile).use { outputStream ->
            inputStream.copyTo(outputStream)
        }
    }
    return destFile
}

情况1:加载栅格(Raster)MBTiles

// 在Activity/Fragment的onCreate里执行
val mapView = findViewById<MapView>(R.id.mapView)
mapView.onCreate(savedInstanceState)

// 1. 复制MBTiles到私有目录
val mbtilesFile = copyMbtilesToPrivateDir(this, "map.mbtiles")

// 2. 初始化TileStore(绑定MBTiles文件)
val tileStore = TileStore.create(
    this,
    TileStoreOptions.Builder()
        .path(mbtilesFile.absolutePath)
        .build()
)

// 3. 加载空白Style,添加离线栅格源和图层
mapView.getMapboxMap().loadStyle(Style.EMPTY) { style ->
    // 创建绑定TileStore的栅格源
    val rasterSource = RasterSource.Builder("offline-raster",
        TileStoreSourceOptions.Builder()
            .tileStore(tileStore)
            .tileStoreId("my-offline-raster") // 自定义瓦片集合ID,可任意命名
            .build()
    )
        .tileSize(256) // 要和你的MBTiles元数据里的tile_size一致
        .build()

    style.addSource(rasterSource)

    // 添加栅格渲染图层
    style.addLayer(
        RasterLayer.Builder("offline-raster-layer", "offline-raster")
            .build()
    )

    // 可选:设置地图初始视角(用MBTiles元数据里的bounds)
    // mapView.getMapboxMap().setCamera(CameraOptions.Builder()
    //     .center(LatLng(中心纬度, 中心经度))
    //     .zoom(10.0)
    //     .build())
}

情况2:加载矢量(Vector)MBTiles

矢量MBTiles的核心流程和栅格一致,只是源和图层类型不同,且需要指定MBTiles内部的矢量图层名称(可以用MBTiles Viewer工具查看内部图层):

// 前面的复制文件、TileStore初始化和栅格版完全一致
mapView.getMapboxMap().loadStyle(Style.EMPTY) { style ->
    // 创建绑定TileStore的矢量源
    val vectorSource = VectorSource.Builder("offline-vector",
        TileStoreSourceOptions.Builder()
            .tileStore(tileStore)
            .tileStoreId("my-offline-vector")
            .build()
    )
        .build()

    style.addSource(vectorSource)

    // 添加矢量图层(示例:渲染道路图层,替换为你MBTiles里的实际图层名)
    style.addLayer(
        LineLayer.Builder("roads-layer", "offline-vector")
            .sourceLayer("roads") // 必须和MBTiles内部的图层名一致
            .lineColor(Color.parseColor("#ff0000"))
            .lineWidth(2f)
            .build()
    )

    // 同理,可添加其他矢量图层(比如土地、水域等)
    style.addLayer(
        FillLayer.Builder("land-layer", "offline-vector")
            .sourceLayer("land")
            .fillColor(Color.parseColor("#f0f0f0"))
            .build()
    )
}

三、关键注意事项

  1. MapLibre版本:必须用11.0.0+的版本,TileStore的API在11.x才稳定,低版本可能有兼容性问题。
  2. MBTiles元数据校验:确保你的MBTiles文件是合法的——用MBTiles Viewer工具检查metadata表是否有boundsminzoommaxzoomformat等关键字段,格式错误会导致加载失败。
  3. 权限问题:如果把MBTiles放在外部存储,Android 10+需要用Scoped Storage,推荐直接复制到App私有目录避免权限申请。

四、你的问题逐一解答

  1. Does MapLibre Android support loading MBTiles directly?
    → 是的,但必须通过TileStore组件,不能直接用file://路径加载。
  2. Is there a working Kotlin example?
    → 上面的代码就是可运行的完整示例,只需要替换你的MBTiles文件名和矢量图层名即可。
  3. If no, recommended approach?
    → 优先用官方的TileStore方案;如果有特殊需求,可将MBTiles转换为PMTiles(单文件瓦片格式,MapLibre 11.x+支持),转换工具用mbtiles-to-pmtiles;不推荐换SDK,MapLibre是目前开源离线地图的最优选择之一。

调试技巧

如果加载失败,去Logcat里搜索Tag为MapLibre的日志,里面会给出具体错误原因——比如MBTiles文件损坏、元数据缺失、路径错误等,方便快速定位问题。

火山引擎 最新活动