Upgrade from 0.3.x to 0.4
The 0.4 series replaces the MapLibre Android and iOS SDKs and the WebView
desktop integration with one implementation on the
MapLibre Native C API. It
also makes style layers, expressions, sources and map options typed. This
guide applies to the 0.4.0-pre.* pre-releases and to 0.4.0. The
changelog lists every change.
1. Update the dependency
dependencies:
maplibre: ^0.4.0-pre.1
The packages need Dart 3.13 and Flutter 3.47 or newer.
2. Platform setup
maplibre now uses maplibre_web in the browser and maplibre_native on
Android, iOS, macOS, Windows and Linux. maplibre_android, maplibre_ios
and maplibre_webview are discontinued. If you depend on one of them
directly, remove it.
| Platform | Change |
|---|---|
| Web | maplibre-gl-js v6 loads on its own. Remove the maplibre-gl-js and PMTiles <script> and <link> tags from web/index.html. |
| Android | Requires Android 7.0 (API level 24) and OpenGL ES 3.0. Plain http:// URLs need a network security config. |
| iOS | Requires iOS 15. Swift Package Manager only, CocoaPods is not supported. |
| macOS | Requires macOS 14.3. Swift Package Manager only. Works out of the box, maplibre_webview is no longer needed. |
| Windows | Works out of the box, maplibre_webview is no longer needed. |
| Linux | New. Needs the GTK and libepoxy development packages to build. |
See Platform setup for the details.
maplibre-gl-js v6 requires WebGL 2, returns nested objects in GeoJSON
feature properties as maps instead of JSON strings, and sets
zoomLevelsToOverscale to 4 by default, which can change label rendering and
featuresAtPoint() results. See the
maplibre-gl-js migration guide.
3. Map options
The style and the initial camera are typed, so they are no longer guessed:
// 0.3
MapOptions(
initStyle: 'https://demotiles.maplibre.org/style.json',
initCenter: Geographic(lon: 9.17, lat: 47.68),
initZoom: 7,
)
// 0.4
MapOptions(
style: MapStyle.url('https://demotiles.maplibre.org/style.json'),
initCamera: InitialCamera.position(
center: Geographic(lon: 9.17, lat: 47.68),
zoom: 7,
),
)
initStyleis nowstyle, aMapStyle.url,MapStyle.json,MapStyle.assetorMapStyle.file. The map loads a new style whenstylechanges, soMapController.setStylewas removed.initCenter,initZoom,initBearingandinitPitchare nowinitCamera, anInitialCamera.positionorInitialCamera.bounds. WithoutinitCamera, the map starts at the camera of the style instead of zoom 0.androidMode,androidTextureMode,androidTranslucentTextureSurface,androidForegroundLoadColor,webviewDebugModeand the deprecatedpitchwere removed.
4. Style layers and expressions
Style layers take typed properties and
expressions instead of paint and layout
maps. The annotation layers take expressions too.
// 0.3
LineStyleLayer(
id: 'route',
sourceId: 'route',
paint: {'line-color': '#FF0000', 'line-width': 3},
layout: {'line-cap': 'round'},
)
// 0.4
LineStyleLayer(
id: 'route',
sourceId: 'route',
color: const .literal(Color(0xFFFF0000)),
width: const .literal(3),
cap: const .literal(LineCap.round),
)
Expression.raw takes the JSON of a single property, and
StyleLayer.fromJson the JSON of a whole layer.
5. Sources and layers of the style
style.layers and style.sources replace the layer and source methods of
StyleController:
| 0.3 | 0.4 |
|---|---|
style.addLayer(layer) |
style.layers.add(layer) |
style.removeLayer(id) |
style.layers.remove(id) |
style.addSource(source) |
style.sources.add(source) |
style.removeSource(id) |
style.sources.remove(id) |
style.updateGeoJsonSource(...) |
style.sources.updateGeoJsonData(...) or updateGeoJsonUrl(...) |
style.getLayerIds() |
style.layers.map((layer) => layer.id) |
style.getAttributions() |
style.attributions |
Sources are sealed classes with named constructors:
| 0.3 | 0.4 |
|---|---|
GeoJsonSource(data: url) |
GeoJsonSource.url(url: url) |
GeoJsonSource(data: geoJson) |
GeoJsonSource.data(data: geoJson) |
ImageSource(url: url) |
ImageSource.url(url: url), or .bytes / .provider |
VectorSource(url: tileJsonUrl) |
VectorSource.url(url: tileJsonUrl) |
VectorSource(tiles: [...]) |
VectorSource.tiles(tiles: [...]) |
RasterSource, RasterDemSource |
.url and .tiles, like VectorSource |
VideoSource(urls: [...]) |
VideoSource.urls(urls: [...]) |
VideoSource.coordinates is a LngLatQuad, like ImageSource.coordinates.
VideoSource is only supported on web.
6. Images
addImage, addImages and addImageFromAssets take a pixelRatio of image
pixels per logical pixel, 1 by default, instead of the device pixel ratio.
Images now show at the same logical size on every screen, so they grow on
high-DPI screens. Pass the ratio the image was made for to keep their size:
await style.addImage('marker', bytes, pixelRatio: 2);
addImageFromCanvas and addImageFromIconData take their sizes in logical
pixels.
7. Geometry types
LngLatBoundsis replaced by geobase'sGeoBoxinfitBounds,getVisibleRegion,MapOptions.maxBoundsand offline regions.GeoBox.from(points)replacesLngLatBounds.fromPoints(points).maplibreexports only the geobase types its API uses. Importpackage:geobase/geobase.dartfor the others.
8. Feature queries
featuresAtPointandfeaturesInRectreturn aFuture, soawaitthem.queryLayersandQueriedLayerwere removed. UsefeaturesAtPointwithlayerIds, andRenderedFeature.layerId,sourceIdandsourceLayer.
9. User location and permissions
PermissionManager, MapController.enableLocation, trackLocation,
userLocationIsSupported, BearingRenderMode and BearingTrackMode were
removed. Show the location with a UserLocationLayer
and ask for permissions with geolocator or permission_handler.
MapControlButtons takes tracking and onTrackingPressed instead of
showTrackLocation.
10. Offline regions
OfflineManager.downloadRegion takes an OfflineRegionDefinition:
// 0.3
manager.downloadRegion(
mapStyleUrl: styleUrl,
bounds: bounds,
minZoom: 10,
maxZoom: 14,
pixelDensity: 1,
);
// 0.4
manager.downloadRegion(
definition: OfflineTilePyramidRegionDefinition(
styleUrl: styleUrl,
bounds: bounds,
minZoom: 10,
maxZoom: 14,
pixelRatio: 1,
),
);
OfflineRegion holds the definition, DownloadProgress holds an
OfflineRegionStatus, and download errors are an OfflineResourceException
or an OfflineTileCountLimitException. setOfflineTileCountLimit and
runPackDatabaseAutomatically were removed. See
Offline & Cache.
11. Web gestures
Map gestures are recognized in Flutter on every platform, also on web.
MapLibre GL JS's keyboard navigation and Shift + drag box zoom are no longer
available. Widgets over the map no longer need a PointerInterceptor.
12. Native platforms
MapLibre Native has no globe projection, so
setProjection(MapProjection.globe) keeps Mercator on Android, iOS and
desktop.