vtzero_dart
A Dart/Flutter FFI wrapper around the vtzero C++ library for decoding Mapbox Vector Tiles (MVT).
Overview
vtzero_dart provides Dart bindings to the vtzero C++ library, a minimalist and efficient implementation of the Mapbox Vector Tile Specification 2.x. This enables decoding vector tile data directly in Dart/Flutter applications using native code.
Features
- Native Performance: Direct FFI bindings to C++ for tile decoding
- Cross-Platform: Supports Android (API 24+) and iOS (13.0+)
- Minimal Dependencies: Leverages the lightweight vtzero library
- Two API Styles:
- Core API: Direct vtzero interface with manual memory management
- Adapter API: Drop-in replacement for the
vector_tilepackage with native-acceleratedtoGeoJson()
- Full Tile Access: Iterate through layers, features, properties, and geometry
- GeoJSON Support: Convert features to GeoJSON coordinates with proper Web Mercator projection
Installation
Add this to your package's pubspec.yaml file:
dependencies:
vtzero_dart: ^0.0.14
Then run:
flutter pub get
Note: This package includes pre-built native binaries for supported platforms. No additional build steps are required when installing from pub.dev. The native libraries are automatically loaded based on your platform and architecture.
Usage
Core API (No External Dependencies)
The core API provides direct access to vtzero functionality:
import 'package:vtzero_dart/vtzero_dart.dart';
// Load tile bytes
final Uint8List tileBytes = ...; // from network, file, etc.
// Decode tile
final tile = VtzTile.fromBytes(tileBytes);
// Iterate through layers
final layers = tile.getLayers();
for (final layer in layers) {
print('Layer: ${layer.name}');
print('Extent: ${layer.extent}');
print('Version: ${layer.version}');
// Get features
final features = layer.getFeatures();
for (final feature in features) {
print('Geometry type: ${feature.geometryType}');
// Access properties
final properties = feature.getProperties();
properties.forEach((key, value) {
print(' $key: $value');
});
// Decode geometry to tile coordinates
final geometry = feature.decodeGeometry();
// geometry is List<List<List<int>>> - rings/lines of [x,y] points
// Or convert directly to GeoJSON coordinates (Web Mercator)
final geoJsonCoords = feature.toGeoJson(
extent: layer.extent,
tileX: 0,
tileY: 0,
tileZ: 0,
);
// Clean up
feature.dispose();
}
layer.dispose();
}
tile.dispose();
Adapter API (vector_tile Compatibility)
Use vtzero_dart as a drop-in replacement for the vector_tile package with native-accelerated GeoJSON conversion:
import 'package:vtzero_dart/vector_tile_adapter.dart';
import 'package:vector_tile/util/geojson.dart' as geo;
// Create VectorTile using vtzero backend
final vectorTile = VectorTileVtzero.fromBytes(bytes: tileBytes);
// Use familiar vector_tile API
for (final layer in vectorTile.layers) {
print('Layer: ${layer.name}');
for (final feature in layer.features) {
// This calls native optimized toGeoJson!
final geoJson = feature.toGeoJson(x: 0, y: 0, z: 0);
if (geoJson != null) {
print('Type: ${geoJson.geometry?.type}');
// Work with GeoJSON as usual...
}
}
}
API Reference
Core Classes
VtzTile
Represents a decoded vector tile.
VtzTile.fromBytes(Uint8List bytes)- Decode a tile from raw bytesList<VtzLayer> getLayers()- Get all layers in the tileVtzLayer? getLayer(String name)- Get a layer by namevoid dispose()- Free native resources
VtzLayer
Represents a layer within a tile.
String name- Layer nameint extent- Tile extent (typically 4096)int version- MVT version (typically 2)List<VtzFeature> getFeatures()- Get all features in the layervoid dispose()- Free native resources
VtzFeature
Represents a feature within a layer.
VtzGeometryType geometryType- Geometry type (point, linestring, polygon, unknown)int? id- Optional feature IDMap<String, dynamic> getProperties()- Decode feature propertiesList<List<List<int>>> decodeGeometry()- Decode geometry to tile coordinatesList<List<List<double>>> toGeoJson({required int extent, required int tileX, required int tileY, required int tileZ})- Convert to GeoJSON coordinates (Web Mercator projection)void dispose()- Free native resources
VtzGeometryType
Enum for geometry types:
VtzGeometryType.unknownVtzGeometryType.pointVtzGeometryType.linestringVtzGeometryType.polygon
Adapter Classes
VectorTileVtzero
Drop-in replacement for VectorTile from the vector_tile package.
VectorTileVtzero.fromBytes({required Uint8List bytes})- Create from bytes using vtzero decoderList<VectorTileLayer> layers- Access layers
VectorTileFeatureVtzero
Extends VectorTileFeature with native-accelerated toGeoJson().
Memory Management
The core API requires manual memory management. Always call dispose() on tiles, layers, and features when done:
// Good practice
final tile = VtzTile.fromBytes(bytes);
try {
final layers = tile.getLayers();
for (final layer in layers) {
try {
final features = layer.getFeatures();
for (final feature in features) {
try {
// Use feature...
} finally {
feature.dispose();
}
}
} finally {
layer.dispose();
}
}
} finally {
tile.dispose();
}
The adapter API handles memory management internally through closures, but native objects remain in memory until the VectorTileVtzero instance is garbage collected.
Platform Support
- Android: API level 24+ (Android 7.0+)
- iOS: 13.0+
- Architecture: ARM64, ARMv7 (Android), x86_64 simulators
Building from Source
Prerequisites
- Flutter SDK
- C++14 compatible compiler
- CMake 3.10+
- Git (for submodules)
Setup
# Clone with submodules
git clone --recursive https://github.com/yourusername/vtzero_dart.git
cd vtzero_dart
# Or if already cloned, initialize submodules
git submodule update --init --recursive
# Get Dart dependencies
flutter pub get
# Regenerate FFI bindings (if needed)
dart run ffigen --config ffigen.yaml
Building Native Libraries for Distribution
This package includes pre-built binaries for supported platforms. For Android and iOS, Flutter's plugin system automatically builds the native code. For desktop platforms (macOS, Linux, Windows), you can build binaries locally:
# Build for current platform only (default)
dart scripts/build_native.dart
# Build for all supported platforms (macOS, Linux, Windows, iOS, Android)
dart scripts/build_native.dart --all
# or
dart scripts/build_native.dart -a
# Build for specific platform(s)
dart scripts/build_native.dart --platform macos
dart scripts/build_native.dart --platform ios
dart scripts/build_native.dart --platform android
dart scripts/build_native.dart --platform linux --platform windows
# or
dart scripts/build_native.dart -p macos -p ios -p android
Platform-Specific Notes:
iOS:
- Can only be built on macOS (requires Xcode)
- Builds for both
arm64(device) andx86_64(simulator) architectures - Uses CMake with iOS toolchain configuration
Android:
- Can be built on macOS, Linux, or Windows
- Requires Android NDK (set
ANDROID_NDK_HOMEenvironment variable) - Builds for:
arm64-v8a,armeabi-v7a,x86,x86_64 - Minimum API level: 24 (Android 7.0+)
Cross-Compilation:
- macOS can build for: macOS, iOS
- Linux can build for: Linux (and Android if NDK is available)
- Windows can build for: Windows (and Android if NDK is available)
- On macOS with Apple Silicon, you can build for both
arm64andx86_64architectures - For true multi-platform builds, use CI/CD pipelines with multiple runners
This will:
- Detect your platform and architecture (macOS, Linux, Windows, etc.)
- Build the native library using CMake
- Place the built library in
lib/native/{platform}/{architecture}/
Note: Android and iOS libraries are automatically built by Flutter's plugin system (ffiPlugin: true). The build script is primarily for desktop platforms or when you need to distribute pre-built binaries.
Supported Platforms:
- macOS (arm64, x86_64)
- Linux (x86_64, arm64, arm)
- Windows (x64)
- Android (arm64-v8a, armeabi-v7a, x86, x86_64)
- iOS (arm64, x86_64 for simulator)
Note: This package does not require the native-assets experiment. Android and iOS libraries are built automatically by Flutter's plugin system. Desktop platforms can use pre-built binaries placed in lib/native/ or build from source.
Build Native Code (Legacy/Development)
For development and testing, you can also build using Flutter's build system:
iOS
cd example
flutter build ios
Android
cd example
flutter build apk
Example App
See the example directory for a complete Flutter app demonstrating usage:
cd example
flutter run
The example app loads a sample vector tile and displays information about its layers, features, and geometry.
Dependencies
- ffi - Dart FFI utilities
- fixnum - Fixed-width integers
- vector_tile - For adapter API compatibility
Native Dependencies (included as submodules)
Architecture
┌─────────────────────────────────────┐
│ Dart Application │
├─────────────────────────────────────┤
│ vtzero_dart API (Core or Adapter) │
├─────────────────────────────────────┤
│ Dart FFI Bindings │
├─────────────────────────────────────┤
│ C++ Wrapper (vtzero_dart.h) │
├─────────────────────────────────────┤
│ vtzero C++ Library (header-only)│
├─────────────────────────────────────┤
│ protozero C++ Library (header-only)│
└─────────────────────────────────────┘
The library consists of:
- C++ wrapper (
src/vtzero_wrapper.cpp) - Provides C-compatible FFI interface - FFI bindings (
lib/vtzero_dart_bindings_generated.dart) - Auto-generated with ffigen - Dart wrapper (
lib/src/) - Provides idiomatic Dart API - Adapter layer (
lib/vector_tile_adapter.dart) - Optional compatibility with vector_tile package
License
MIT License - see LICENSE file for details.
Third-Party Licenses
This project includes the following third-party components:
- vtzero - Copyright (c) 2017, Mapbox (BSD-2-Clause License)
- protozero - Copyright (c) 2022, Mapbox (BSD-3-Clause License)
See third_party/ directory for complete license texts.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Troubleshooting
iOS Build Issues
If you encounter build errors on iOS:
cd example/ios
pod install
Android Build Issues
Ensure you have NDK installed and ndkVersion is set in your app's build.gradle.
Binding Generation
If FFI bindings are out of sync:
dart run ffigen --config ffigen.yaml
Acknowledgments
- Mapbox for the vtzero and protozero libraries
- The Mapbox Vector Tile specification maintainers