Skip to content

Local development

This page explains how to work on the packages themselves. To use the packages in your app, read How to setup.

Repository layout

The repository is a pub workspace. One flutter pub get in its root resolves every package:

Path Content
packages/maplibre The app-facing package
packages/maplibre_platform_interface The platform interface and the shared gesture recognizer
packages/maplibre_web The web implementation on MapLibre GL JS
packages/maplibre_native The implementation for every other platform
examples The example app, which also runs the integration tests
tool Scripts for code generation and releases
website This documentation

Get started

You need Flutter 3.47 or newer. Clone the repository and get the dependencies:

git clone https://github.com/josxha/flutter-maplibre
cd flutter-maplibre
flutter pub get

Then run the example app:

cd examples
flutter run -d windows   # or chrome, or an Android device

On Windows, Flutter's own requirements apply: Visual Studio 2022 with the Desktop development with C++ workload. On Windows, the device needs a Vulkan 1.1 driver. Android renders with OpenGL ES 3.0 by default; to try the Vulkan build there, uncomment the hooks: block at the end of the root pubspec.yaml and keep only its backend entry.

The MapLibre Native C library

The Dart binding maplibre_native_ffi comes from pub.dev, and its build hook downloads the prebuilt C library of its release for each target. You only need to build the library yourself to change it or to try an unreleased version.

Build on Windows

Clone maplibre-native-ffi, for example next to this repository, at the release tag that the workspace resolves to. Install:

  • Visual Studio 2022 with the Desktop development with C++ workload
  • Standalone LLVM, so that C:\Program Files\LLVM\bin\clang-cl.exe exists
  • CMake and Ninja
  • Rust, and cargo install cargo-about --version 0.9.2 --locked --features cli
  • Git for Windows, for Git Bash

Then, in Git Bash from the clone:

bash .mise/bin/sync-submodules
source .mise/bin/windows-msvc-env.sh
cmake --preset windows-x64-vulkan -DBUILD_TESTING=OFF
cmake --build --preset windows-x64-vulkan

A first build takes most of an hour. -DBUILD_TESTING=OFF leaves out the C library's tests, which would also need the Vulkan SDK.

MSVC and LLVM versions

The MSVC standard library requires a matching Clang version: MSVC 14.44 needs LLVM 19 or newer. With an older LLVM, use an older MSVC toolset such as 14.37. Install it in the Visual Studio Installer and load its environment instead of sourcing windows-msvc-env.sh, for example with vcvars64.bat -vcvars_ver=14.37.

Build for Android

The Android presets build against the Android SDK and NDK from ANDROID_HOME. Build android-arm64-egl for devices or android-x64-egl for emulators, the same way as the Windows preset above. The development overview lists the requirements and how to install the pinned SDK with mise. The android-*-vulkan presets build the Vulkan opt-in.

Use the local build

Name the clone's build root in the root pubspec.yaml:

hooks:
  user_defines:
    maplibre_native_ffi:
      local_build: ../maplibre-native-ffi/build

The hook takes <preset>/install under it for each target, so one setting serves every platform and Android ABI you have built. Without a backend entry it takes the platform's default preset (-egl on Android); select backend: { android: vulkan } to use an android-*-vulkan build. Remove local_build to go back to the prebuilt library.

Tests

# Unit tests of the gesture recognizer
cd packages/maplibre_platform_interface && flutter test

# Unit tests of the app-facing package
cd packages/maplibre && flutter test

# Loads the C library and opens a runtime and a map
cd packages/maplibre_native && flutter test

# Integration tests on a device: windows, linux, macos, an iOS simulator or
# an Android device
cd examples && flutter test integration_test/all_test.dart -d windows

# Integration tests on web, with chromedriver running on port 4444
cd examples && flutter drive --driver test_driver/integration_test.dart \
  --target integration_test/all_test.dart -d web-server --browser-name chrome

CI runs the integration tests on every platform. Its runners have no GPU, so the maps render in software there.

Code generation

maplibre_native reaches its platform plugins through ffigen on Windows and jnigen on Android. The generators run from tool/codegen, a package outside the workspace, which keeps the binding's build hook out of code generation:

cd tool/codegen
dart pub get
dart run ffigen.dart   # after changing windows/include/maplibre_native/maplibre_native_api.h
dart run jnigen.dart   # after changing the Kotlin API; build the example APK in release mode first

Documentation

The website is built with Zensical from mkdocs.yml and website/:

pip install zensical
zensical serve

Before you commit

Format and analyze the code, or install pre-commit and run pre-commit install once to do both on every commit:

dart format .
dart analyze --fatal-warnings --fatal-infos

Design decisions and known gaps are recorded in .agents/decisions.md.