alfa_vector_mbtiles 0.0.6 copy "alfa_vector_mbtiles: ^0.0.6" to clipboard
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 .mbtiles file, no network required.

pub version pub points likes license: MIT platform

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.flutter-io.cn 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 — implements VectorTileProvider, so it composes with MemoryCacheVectorTileProvider, VectorTileLayer, TileProviders, and the whole flutter_map stack.
  • 🗜️ Handles the MBTiles spec for you — gunzips tile_data and applies the TMS row flip (tile_row = 2^z − y − 1) so tiles land in the right place.
  • 📦 Asset bootstrap — copies the bundled .mbtiles asset into the app's databases directory on first run, then memoizes the open Database handle for fast subsequent reads.
  • 🎯 Bounds-checked — out-of-range tile requests throw a typed ProviderException instead of returning garbage, and the renderer transparently falls back to lower zoom levels past maximumZoom.
  • 🪶 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 .mbtiles locally.
  • 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 maximumZoom honest: 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_map v6+ / vector_map_tiles latest 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).

2
likes
140
points
53
downloads
screenshot

Documentation

Documentation
API reference

Publisher

unverified uploader

Weekly Downloads

Offline Mapbox Vector Tiles for flutter_map: a VectorTileProvider that reads gzipped MVT tiles from a local .mbtiles SQLite file. No network required.

Repository (GitHub)
View/report issues

Topics

#mbtiles #flutter-map #vector-tiles #offline-maps #maps

License

MIT (license)

Dependencies

flutter, flutter_map, latlong2, path, sqflite, vector_map_tiles

More

Packages that depend on alfa_vector_mbtiles