alfa_vector_mbtiles 0.0.6
alfa_vector_mbtiles: ^0.0.6 copied to clipboard
Offline Mapbox Vector Tiles for flutter_map: a VectorTileProvider that reads gzipped MVT tiles from a local .mbtiles SQLite file. No network required.
alfa_vector_mbtiles #
Offline Mapbox Vector Tiles for
flutter_map— straight from a local.mbtilesfile, no network required.
alfa_vector_mbtiles is a tiny, dependency-light VectorTileProvider that reads
gzipped Mapbox Vector Tiles (MVT/PBF) out of a standard .mbtiles SQLite database and
feeds them to vector_map_tiles +
flutter_map. The result is a fully rendered,
pannable, zoomable vector basemap that works 100% offline — ideal for aviation,
maritime, field-work, or any app that has to keep a map alive without connectivity.
It powers the offline charts in the Alfaero flight apps.
Screenshots #
⚠️ The images below are placeholders. Drop your real captures over the files in
doc/screenshots/(keep the same filenames) and they will appear here and on the pub.dev gallery automatically.
| Day basemap | Night basemap | Offline |
|---|---|---|
![]() |
![]() |
![]() |
| Light vector theme | Dark vector theme | Tiles read from local .mbtiles |
Why vector .mbtiles? #
Raster .mbtiles |
Vector .mbtiles (this package) |
|
|---|---|---|
| File size | Large (one PNG per tile/zoom) | Small (one PBF describes many zooms) |
| Re-styling | Baked in — re-render to change colors | Instant — swap the style/theme at runtime |
| Zoom sharpness | Pixelated on over-zoom | Crisp — geometry is re-rendered per zoom |
| Day/Night/VFR | 3× the storage | Same file, 3 themes |
| Offline | ✅ | ✅ |
You ship one .mbtiles file and render it with as many MapLibre/Mapbox styles as you like.
Features #
- 🛰️ Offline-first — every tile comes from the local SQLite file; zero HTTP requests.
- 🧩 Drop-in for
vector_map_tiles— implementsVectorTileProvider, so it composes withMemoryCacheVectorTileProvider,VectorTileLayer,TileProviders, and the wholeflutter_mapstack. - 🗜️ Handles the MBTiles spec for you — gunzips
tile_dataand applies the TMS row flip (tile_row = 2^z − y − 1) so tiles land in the right place. - 📦 Asset bootstrap — copies the bundled
.mbtilesasset into the app's databases directory on first run, then memoizes the openDatabasehandle for fast subsequent reads. - 🎯 Bounds-checked — out-of-range tile requests throw a typed
ProviderExceptioninstead of returning garbage, and the renderer transparently falls back to lower zoom levels pastmaximumZoom. - 🪶 Lightweight — pure Dart on top of
sqflite; no native plugin to register.
Supported platforms #
| Platform | Status | Notes |
|---|---|---|
| Android | ✅ | via sqflite |
| iOS | ✅ | via sqflite |
| Desktop (Win/macOS/Linux) | ⚠️ | works with sqflite_common_ffi registered as the database factory |
| Web | ❌ | sqflite has no web backend |
Installation #
flutter pub add alfa_vector_mbtiles
This also pulls the peers you'll use in the layer: flutter_map, vector_map_tiles,
and latlong2.
Add your .mbtiles as an asset in pubspec.yaml:
flutter:
assets:
- assets/basemap.mbtiles
Quick start #
// `Theme` is hidden from material because `vector_tile_renderer` exports the
// map render `Theme` we use below.
import 'package:flutter/material.dart' hide Theme;
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:vector_map_tiles/vector_map_tiles.dart';
import 'package:vector_tile_renderer/vector_tile_renderer.dart';
import 'package:alfa_vector_mbtiles/alfa_vector_mbtiles.dart';
class OfflineMap extends StatelessWidget {
const OfflineMap({super.key, required this.theme});
/// A `vector_tile_renderer` Theme built from a MapLibre/Mapbox style JSON.
final Theme theme;
@override
Widget build(BuildContext context) {
return FlutterMap(
// flutter_map v4 API (the version this package depends on):
// use `center`/`zoom` (v6+ renamed these to `initialCenter`/`initialZoom`).
options: MapOptions(
center: LatLng(-23.5505, -46.6333), // São Paulo
zoom: 12,
maxZoom: 18,
),
children: [
VectorTileLayer(
theme: theme,
tileProviders: TileProviders({
// The source name MUST match the `source` used by your style JSON
// (e.g. 'openmaptiles').
'openmaptiles': MemoryCacheVectorTileProvider(
delegate: AlfaVectorMBTilesProvider(
mbtilesPath: 'assets/basemap.mbtiles',
// Max zoom *stored in the file* — not the map's max zoom.
// The renderer over-zooms past this automatically.
maximumZoom: 14,
),
maxSizeBytes: 2 * 1024 * 1024, // 2 MB in-memory tile cache
),
}),
),
],
);
}
}
A complete, runnable app (with a bundled sample .mbtiles and an OSM-Bright style) lives in
example/.
API reference #
AlfaVectorMBTilesProvider #
AlfaVectorMBTilesProvider({
required String mbtilesPath,
int maximumZoom = 16,
});
| Parameter | Type | Default | Description |
|---|---|---|---|
mbtilesPath |
String |
— | Flutter asset path to the .mbtiles file (e.g. assets/basemap.mbtiles). On first read it is copied into the device's databases directory. |
maximumZoom |
int |
16 |
The highest zoom level present in the file. Requests above it are served by over-zooming lower-level tiles — do not set this to the map widget's maxZoom. |
Implements VectorTileProvider
from vector_map_tiles, so it can be wrapped by MemoryCacheVectorTileProvider and handed to
VectorTileLayer / TileProviders.
ProviderException #
Thrown for invalid/out-of-range tile coordinates.
class ProviderException implements Exception {
final Retryable retryable; // Retryable.retry | Retryable.none
final String message;
final int? statusCode;
}
How it works #
flutter_map (VectorTileLayer)
│ asks for tile z/x/y
▼
MemoryCacheVectorTileProvider ← in-memory LRU cache (optional but recommended)
│ cache miss
▼
AlfaVectorMBTilesProvider.provide()
│ validates z/x/y against 2^z bounds
▼
MBTilesUtility.getVectorTileBytes()
│ 1. opens the .mbtiles (copied from asset → databases dir on first call)
│ 2. SELECT tile_data WHERE zoom_level=z AND tile_column=x
│ AND tile_row = (2^z − y − 1) ← TMS flip
│ 3. gunzip(tile_data) → raw MVT/PBF bytes
▼
vector_tile_renderer → painted vector tile
The decoded bytes are standard Mapbox Vector Tiles, so any MapLibre/Mapbox GL style that targets your source layers will render correctly.
Generating a compatible .mbtiles #
The file must contain gzipped MVT tiles in the tiles table (the OpenMapTiles / OpenStreetMap
schema is the common case). Typical toolchains:
- tilemaker — OSM
.pbf→ vector.mbtileslocally. - planetiler — fast OSM → vector
.mbtiles. - tippecanoe — GeoJSON/feature data → vector
.mbtiles. - Extract a region from an existing planet PMTiles/MBTiles set.
Pair it with an OpenMapTiles-compatible style (e.g. OSM Bright, Positron, Dark Matter)
converted to a vector_tile_renderer Theme via ThemeReader.
Performance tips #
- Always wrap the provider in
MemoryCacheVectorTileProvider— vector tiles are expensive to decode; caching the decoded geometry avoids re-reading SQLite on every frame. - Keep
maximumZoomhonest: a too-high value makes the renderer ask for tiles that don't exist; a too-low value triggers heavy over-zoom rendering. - Ship a region-trimmed
.mbtiles, not the planet — startup copies the asset to disk once. - For very large files, consider lazy-copying or streaming the asset instead of bundling it.
Troubleshooting #
| Symptom | Likely cause |
|---|---|
| Blank/empty map, no errors | The TileProviders key doesn't match the source id in your style JSON. |
Invalid tile coordinates |
The map requested a tile outside 2^z — usually a wrong maximumZoom. |
| Tiles shifted/flipped | Your .mbtiles is XYZ, not TMS; this package assumes TMS row order (per the MBTiles spec). |
FormatException while decoding |
tile_data isn't gzipped MVT (e.g. it's a raster mbtiles). This package is vector only. |
| Crashes on desktop | Register sqflite_common_ffi as the database factory in main(). |
Roadmap #
- ❌ Optional XYZ (non-flipped) tile order support.
- ❌ Pluggable asset → disk copy strategy (stream large files).
- ❌ Desktop/FFI first-class support out of the box.
- ❌
flutter_mapv6+ /vector_map_tileslatest compatibility track.
Contributions welcome — see issues.
Credits #
This package builds on the original vector_mbtiles approach for reading vector tiles from
MBTiles in flutter_map, repackaged and maintained as alfa_vector_mbtiles for the Alfaero apps.
Thanks to the upstream authors and the flutter_map / vector_map_tiles communities.
License #
MIT © Levi Costa.
Map data and styles you render are subject to their own licenses (e.g. OpenStreetMap / OpenMapTiles require attribution — keep it visible).



