NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev · #1133 most downloaded on pub.dev
A common platform interface for the maplibre_gl plugin. This package is only intended to be used by the maplibre_gl package.
Last release 28 days ago
10 Sep 2026
Release timing varies
gaps range from 2 weeks to 9 months
Nearly every release is documented
notes for 15 of 16 stable releases
Nothing withdrawn
no release was ever pulled
3 years old
16 releases · first in 2023
Note: 0.27.0 does not build on Android for apps created with Flutter 3.44 or later, failing at configuration with Could not find method kotlin() . Tha
Note: 0.27.0 does not build on Android for apps created with Flutter 3.44 or later, failing at configuration with Could not find method kotlin(). That is fixed here, and any android.builtInKotlin=true or hand-applied Kotlin plugin workaround can be removed. This release also clears a crash that has been hitting iOS apps with custom headers since 0.26.2.
Could not find method kotlin(). Those apps carry android.builtInKotlin=false, and the plugin took AGP 9 to mean AGP compiles Kotlin itself, so nothing did. The plugin now applies the Kotlin Gradle Plugin whenever AGP has not taken Kotlin over, and the android.builtInKotlin=true workaround can be removed (#1008).EXC_BAD_ACCESS crashes with a map on screen, introduced in 0.26.2 alongside custom headers. Every request got its own URLSession, and a tile cancelled at the moment it completed was released twice from two threads. Intercepted requests now share one session with a synchronized teardown, and apps that never set custom headers skip the interception altogether (#1009).setOfflineMaxConcurrentRequests now also limits requests that carry custom headers (#1009).getListOfRegions, mergeOfflineRegions and downloadOfflineRegion no longer throw type 'int' is not a subtype of type 'double' for a region whose bounds sit on whole degrees. iOS returns regions as JSON, where 60.0 is written 60, so only regions with a fraction in every coordinate could be read (#241).setCustomHeaders logs header names instead of header values. An API key or Authorization header sent to a tile provider was written to Logcat and the browser console in plain text, in release builds too (#1015).sprite and glyphs at asset://, because the native engines fetch those themselves; copy the files to disk at startup and reference them with file:// (#338).setStyle accepts a raw JSON string on all three platforms. The API docs said Android only (#1026).invalid source release: 21 (#1018).Full Changelog: v0.27.0...v0.27.1
One column per quarter.
See the top-level CHANGELOG for full details.
LatLng decoded from a platform payload accepts a coordinate that arrives without a fractional part. iOS returns offline regions as JSON, where 60.0 is written 60, which threw type 'int' is not a subtype of type 'double' (#241).…. The old names still work as deprecated aliases, so nothing stops compiling, but any style built with xor was doing something else ( #957 ).
The plugin has a documentation site now, at maplibre.org/flutter-maplibre-gl: a guide for every part of the API, each with a live map you can pan and click.
This release regenerates the whole style property surface from the current MapLibre style spec, closes long-standing gaps between the three platforms, and cuts start-up time and the cost of large data updates. Upgrading costs little: the only compile-time change is SourceProperties.copyWith moving to named parameters, plus one small change for Android apps and one or two for web apps, all below.
onStyleLoadedCallback, which fires again after every recreation, rather than in onMapCreated or initState. See the migration guide (#805).maplibre-gl.js script tag and the maplibre-gl.css link tag from web/index.html: if they stay, your pinned copy silently overrides the version the plugin is tested against. See the migration guide (#928).MapLibreMap.webLibrarySource at a version 5 build to keep those browsers working. Version 6 also slices vector tiles instead of overscaling them, so queryRenderedFeatures can return a different set of features. See the migration guide (#943).SourceProperties.copyWith takes named parameters instead of a dozen required positional ones, so props.copyWith(cluster: true) works and future spec additions stop breaking every caller. Calls that passed values positionally need the parameter names added (#957).Expressions.xor never meant xor: ^ is the style spec's exponentiation operator, so the expression raised the first input to the power of the second. It is now Expressions.power, and Expressions.modulo replaces the misspelled Expressions.precent. The old names still work as deprecated aliases, so nothing stops compiling, but any style built with xor was doing something else (#957).mapboxTileCountLimitExceeded to tileCountLimitExceeded and mapboxInvalidRegionDefinition to invalidRegionDefinition. When they fire does not change, but a catch matching either old PlatformException code needs the new one (#956).addColorReliefLayer() colours the terrain by elevation from a raster DEM source, the hypsometric tint of a physical map. The colour ramp is a colorReliefColor expression over Expressions.elevation, and colorReliefOpacity sets how strongly it covers what is below. See the color relief guide (#958).addBackgroundLayer() paints the whole map with backgroundColor or tiles it with backgroundPattern, the one layer type with no source. Pass belowLayerId to place it under the layers it backs. Most published styles already carry a layer called background, so reusing that id fails with layerAlreadyExists. Changing its properties after adding it can stop it drawing while the style's own background layer is still there (maplibre-native#4502). See the background layer guide (#959).setProjection() switches between the mercator, globe and vertical-perspective projections, or interpolates between them by zoom. setTerrain() raises the map by the elevation of a raster DEM source, with null to flatten it again, and setSky() draws the sky and the atmosphere above the horizon. All three throw an UnsupportedError on Android and iOS, where MapLibre Native implements none of them yet. See the globe, terrain and sky guide (#960).textVariableAnchorOffset on symbols, hillshadeMethod and hillshadeIlluminationAltitude for multidirectional hillshading. New expressions: Expressions.distance, within, indexOf, slice and elevation (#957).MapLibreMap.preWarm() starts the map engine during app start-up, for apps whose first screen is a map. Saves roughly 170 to 480 ms on Android, 45 to 165 ms on iOS and 10 to 50 ms on web (#867).setFeatureState, getFeatureState, removeFeatureState) works on Android as well as web, so single features can be restyled without re-feeding the source. iOS throws; its SDK does not expose the API yet. promoteId stays web-only, so Android features need a top-level id in the GeoJSON. See the feature state guide (#889).exportOfflineDatabase() writes a shareable copy, mergeOfflineRegions() imports one (now on iOS too), and getOfflineDatabasePath() locates the store. See the offline regions guide (#886).locationSource: ManualLocationSource() plus controller.updateManualLocation(). See the user location guide (#840).getClusterExpansionZoom() gives the zoom at which a cluster splits, so a cluster tap can zoom to exactly that instead of guessing with zoom + 2. getClusterLeaves() and getClusterChildren() read the points behind a cluster. All three take the cluster feature's cluster_id. See the cluster guide (#896).getLayerProperties() and getSourceProperties() read a layer's or source's properties by id, in the same shape on every platform, or null if the id is unknown. On iOS only what came with the style is readable, so a layer or source you added at runtime answers null there while Android and web answer normally (#513, #985).setLight() sets the style's light source, which shades extruded geometries: anchor, position, color and intensity. Android and iOS take constant values, web also accepts expressions; Android answers INVALID_ARGUMENT for a value it cannot take. See the globe, terrain and sky guide (#960).setPadding() keeps map content centred while a bottom sheet or side panel covers part of the map, instead of passing padding to every camera call (#258).pauseMap() and resumeMap() stop and restart rendering for a map that is alive but off screen, such as one on an inactive tab. No-op on web (#805).setTrackingCameraOptions() pitches the camera without giving up the active tracking mode, for a navigation-style view that stays tilted while it keeps following the user. On web it throws an UnsupportedError. See the user location guide (#888).setGlobalStateProperty() sets a value in the style's global state, which the Expressions.globalState expression reads, so one switch restyles any number of layers at once. Android and iOS throw an UnsupportedError. See the expressions guide (#960).MapLibreMap.webLibrarySource chooses where MapLibre GL JS comes from: the build the plugin is tested against, a self-hosted copy, or one the page loads itself. MapLibreMap.ensureWebLibraryLoaded() completes once MapLibre GL JS is loaded, for calling into it directly, for example addProtocol (#928).fillExtrusionRoundedCornerDistance rounds the corners of extruded shapes. Its generated dartdoc still reads not on js, because the pinned style spec records MapLibre GL JS support for it as an open issue; it shipped in GL JS 6.2.0 and works on web (#957).clusterMinPoints on a GeoJSON source sets how many points have to fall together before they become a cluster, instead of the fixed default of two (#957, #981).attributionButtonColor tints the attribution button, for styles where the default tint is hard to see. No effect on web (#805).LocationEnginePlatforms.iOS takes intervalMs and pulseWindowMs to pulse GPS instead of tracking continuously, easing battery use on maps that stay open a long time. The default keeps continuous tracking (#901).volatile on vector, raster and raster-dem sources keeps their tiles out of the on-disk cache, for tiles that change often or must not be stored. The iOS SDK exposes no equivalent and MapLibre GL JS will not implement one, so it has no effect there (#957, #981).iconOverlap and textOverlap on symbols, fillLayerOpacity and lineLayerOpacity, resampling on raster and hillshade layers, filter on GeoJSON sources, the custom raster-dem encoding with its factors, and the Expressions.globalState, join and split expressions. Android and iOS ignore them, except the custom encoding, which now throws, and join and split, which work on Android since 13.5.0 (#957, #981).addImage are visible again, at the right size on high-density screens. Since 0.26.0 they could be dropped whenever draggable annotations were in use, which is the default. Undecodable bytes now report a clear error instead of crashing (#866, #868).addSymbol are visible again on styles whose glyph server does not host the old default font; a missing font used to hide the whole symbol, icon included. The default is now Noto Sans Regular; for another font use addSymbolLayer with textFont (#940).hillshadeShadowColor and its three companions became arrays in MapLibre Native 6.24 for multidirectional hillshading, so a single value was rejected with Expected array<color> but found string instead and the layer silently kept the default black and white. A single value is now wrapped for you on Android and iOS, and a list is passed through (#957).queryRenderedFeaturesInRect() applies the filter it is given; no platform decoded it, so the answer held every feature in the rectangle. Note that this call takes the filter as a JSON string, unlike queryRenderedFeatures() (#949, #953).onMapCreated included, used to wait forever for a map that never arrived, with only an unhandled error in the console (#943).OfflineRegion (#886).setLayerProperties() works on fill-extrusion and heatmap layers too; both used to answer UNSUPPORTED_LAYER_TYPE (#960).maxzoom on a GeoJSON source is applied again. The converter read a camel-cased key the Dart side never sends, so the value was dropped on Android while iOS and web honoured it (#981).queryRenderedFeatures() and querySourceFeatures() say what is wrong with a call they cannot answer: STYLE_NOT_READY before the style has loaded, INVALID_ARGUMENT for a missing sourceId, layerIds or query geometry. The failure used to arrive as a bare error carrying a NullPointerException message (#954).type 'Null' is not a subtype of type 'Map<String, dynamic>' (#865).queryRenderedFeatures() and querySourceFeatures() no longer skip a feature that failed to serialize without telling you, and no longer hang on a call they cannot answer, such as one made before the style has loaded (#949).queryCameraPosition() returns the camera position even when trackCameraPosition is false, matching Android. It used to return null (#892).controller.cameraPosition no longer sticks on a NaN zoom from a camera event that arrived before the first layout, which misplaced camera-anchored content on maps the user had not touched (#903).onMapIdle now fires, matching Android and iOS; code waiting on it never ran (#857).getFeatureState() returns the state instead of throwing, and reports no state as null rather than an empty map. removeFeatureState(sourceId) with no feature id now resets the whole source instead of doing nothing. A stateKey with no featureId is rejected. Both match Android (#889).querySourceFeatures() now reports an error when it is called before the style has loaded, matching Android and iOS. It answered with an empty list, which the caller cannot tell apart from a source holding no features (#952).queryCameraPosition() is implemented; it used to throw UnimplementedError (#892).updateContentInsets and the new setPadding no longer throw UnimplementedError (#258).showLicensePage() (#895).encoding: "custom" now throws an UnsupportedError from addSource(). MapLibre Native decodes only the mapbox and terrarium formulas and used to read custom tiles as mapbox-encoded, drawing a plausible map from wrong elevations. Only addSource() is checked: the same encoding declared inside MapLibreMap.styleString is still decoded as mapbox without an error. Custom encoding keeps working on web (#981).source-layer or source-id now takes effect (#929).@maplibre/maplibre-gl-style-spec, currently 26.2.1). A weekly workflow reports what a newer release would bring to each platform and opens the update PR, and properties the native SDKs do not implement yet are generated for web only, so upgrading the SDKs unlocks them automatically (#957).sdk-support metadata: iconOverlap reads basic functionality with js (not on android, ios) instead of claiming all three. Where the spec credits a platform whose SDK exposes no such API, the docs say so rather than repeat the spec (#957, #981).addSymbol, addCircle, addLine and addFill when the annotation manager is missing now names the type and both causes: the style has not finished loading, or that type is not in the widget's annotationOrder (#910).android-plugin-annotation-v9 and android-plugin-offline-v9 dependencies are dropped, so apps pull two fewer artifacts (#929).MapLibreMap.useHybridComposition was documented with the wrong default; it has been false since 0.16.0. Its docs and the performance page now say what each value selects (#816).Full Changelog: v0.26.2...v0.27.0
See the top-level CHANGELOG for full details.
The MapLibrePlatform members added below have no default implementation, so an external platform package, or a mock in tests, has to add them. Apps calling the API are unaffected.
shapeStyleProperties() normalizes a style entry into the shape every platform answers with, so getLayerProperties() and getSourceProperties() agree. JavaScript has one number type, so integral values become ints and only genuinely fractional ones stay doubles; read numbers as num (#513).getLayerProperties(layerId) and getSourceProperties(sourceId), returning a layer's or source's properties as a style-spec map, or null for an unknown id (#513).pauseMap() and resumeMap(), forwarded over the channel as map#pause and map#resume, to stop and restart rendering for a map that is alive but off screen (#805).LocationEnginePlatforms.iOS accepts intervalMs and pulseWindowMs, forwarded to the iOS location engine so GPS can be pulsed instead of tracked continuously (#901).LocationSource with ManualLocationSource and PlatformLocationSource, the ManualLocationUpdate model, and setManualLocation, forwarded over the channel as locationComponent#setManualLocation. Which source a map uses arrives as the locationSource key in the map options (#840).MapLibreJsSource, describing where the web implementation loads MapLibre GL JS from. It lives here so apps can configure it through maplibre_gl without importing the web package; Android and iOS ignore it (#928).MapLibreGlobalPlatform, for calls global to the plugin rather than tied to a single map, with MapLibreGlobalMethodChannel as the default. The web package replaces the instance at registration, routing preWarm() and ensureWebLibraryLoaded() to the web implementation (#928).setFeatureState, removeFeatureState and getFeatureState are forwarded over the channel instead of throwing UnimplementedError, so feature state works on Android. iOS throws an UnsupportedError naming the platform (#889).getClusterExpansionZoom, getClusterChildren and getClusterLeaves, forwarded over the channel as source#getCluster*. Each takes the cluster's integer cluster_id; the two feature calls decode a list of JSON strings, as querySourceFeatures does (#896).setTrackingCameraOptions, forwarded over the channel as locationComponent#setTrackingCameraOptions with a tilt and an optional duration. It returns whether the pitch animation ran (#888).Note: This release enforces a minimum Flutter version of 3.29 , which was already required in practice since 0.26.0 but not reflected in the package c
Note: This release enforces a minimum Flutter version of 3.29, which was already required in practice since 0.26.0 but not reflected in the package constraints (#823).
setState) no longer causes unnecessary map updates. Options containing nested lists such as cameraTargetBounds were always treated as changed, even when the value was identical (#849).doubleClickZoomEnabled: false now works correctly. Previously this option was only respected on web, so single taps on Android and iOS always had a ~300 ms delay while the platform waited to rule out a double-tap (#829).setCustomHeaders and setHttpHeaders now correctly apply to all map network requests (tiles, styles, sprites, glyphs). Both APIs were previously silently ignored on iOS (#831).setMapLanguage now correctly changes map labels on non-Mapbox styles (e.g. OpenFreeMap Liberty). Previously, calling setMapLanguage on iOS had no effect and place names were displayed using the style's default language (#830). A new Map Language example in the example app demonstrates this across several languages.rgb(), rgba(), hsl(), hsla(), named colors). Previously only hex colors were supported and anything else rendered as transparent (#832).Full Changelog: v0.26.1...v0.26.2
No platform-interface changes; version aligned with the maplibre_gl 0.26.2 release. See the top-level CHANGELOG for full details.
Note: Several users reported crashes on a range of Android devices after upgrading to 0.26.0, particularly on older / less recent hardware. These issu
Note: Several users reported crashes on a range of Android devices after upgrading to 0.26.0, particularly on older / less recent hardware. These issues are addressed in 0.26.1 (see the Android fixes below).
textureMode when necessary, preventing crashes and rendering and issues with platform views (#816).mapView inside the onResume repaint runnable to avoid NullPointerException when the map is disposed (e.g. dialogs/bottom sheets) before the posted runnable drains (#809).AnnotationManager.dispose() to prevent jumpy drags and _idToAnnotation.containsKey crashes after style reloads on Android and iOS (#806).maplibre-gl JavaScript and CSS version to 5.24.0 in README.md to avoid NoSuchMethodError on MapLibreMap dispose with the previously referenced 4.3.0 version (#814).Full Changelog: v0.26.0...v0.26.1
See the top-level CHANGELOG for full details.
textureMode through the method channel so hybrid composition can enable it when necessary (#816).Removed deprecated typedefs: MaplibreMapController , MaplibreMap , MaplibreStyles . Use MapLibreMapController , MapLibreMap , MapLibreStyles instead.
flutter-maplibre-glThis release resolves numerous long-standing bugs accumulated over the years and completes the transition to WASM compilation for the web platform, ensuring full compatibility with Flutter's modern web toolchain.
It also introduces a new Example App for users to explore the latest features - see maplibre_gl_example for details.
initialCameraPosition is now nullable to support style-defined camera options (#769).LocationEngineAndroidProperties. All fields flattened into LocationEnginePlatforms with nullable platform-specific fields.LocationEnginePlatforms.android(), .iOS(), .web() instead.MaplibreMapController, MaplibreMap, MaplibreStyles. Use MapLibreMapController, MapLibreMap, MapLibreStyles instead.onInfoWindowTapped from MapLibreMapController.removeImageSource (use removeSource) and addLayerBelow (use addImageLayerBelow).takeSnapshot() (#726).featureTapsTriggersMapClick option to control whether feature taps also trigger map click callbacks, defaults to false (#729).onMapClick for all map taps, including after interactive features (#707).pauseOfflineRegionDownload / resumeOfflineRegionDownload to control in-progress downloads.getOfflineRegionStatus returning OfflineRegionStatus with resource counts, bytes, progress and completion.InProgress events now carry completedResourceCount, requiredResourceCount, and completedResourceSize for tile/byte progress in addition to the percentage.clearAmbientCache and resetOfflineDatabase globals to evict unpinned tiles or fully reset the offline DB (in-flight downloads are terminated Dart-side before reset/deletion).setOfflineMaxConcurrentRequests to cap tile concurrency (total on Android, per-host on both) and avoid upstream rate limiting.clusterProperties for clustered GeoJSON sources. Both the simple operator-string form (e.g. {'sum': ['+', ['get', 'x']]}) and the explicit reduce-expression form are now applied natively; previously the property was serialized from Dart but ignored by both native converters (#792).easeCamera accepts an optional CameraAnimationInterpolation to control the animation easing curve (linear, easeInOut, easeOut, fastOutLinearIn). Use CameraAnimationInterpolation.linear for smooth continuous tracking (e.g. following a moving GPS target) without velocity discontinuities between successive calls. Omitting the parameter preserves the previous default behavior (#789).
fastOutLinearIn is implemented via CAMediaTimingFunction(controlPoints: 0.4, 0.0, 1.0, 1.0) (Material Design cubic Bezier).easeCamera, so only linear is distinct — easeInOut, easeOut, and fastOutLinearIn all map to the native ease-in/ease-out. See CameraAnimationInterpolation dartdoc for per-value details.easeCamera is now fully implemented via MapLibre GL JS map.easeTo({easing}). Each interpolation value maps to a cubic-bezier callback (easeInOut → (0.42, 0, 0.58, 1), easeOut → (0, 0, 0.58, 1), fastOutLinearIn → (0.4, 0, 1, 1)). Previously threw UnimplementedError.setMaximumFps to control the preferred frame rate (#739).onMouseMove and added feature state management (setFeatureState, getFeatureState, removeFeatureState) (#718).getLayerVisibility, web snapshot, and map sizing features (#722).enableHighAccuracy and displacement configurable via LocationEnginePlatforms.iOS().enableHighAccuracy, maximumAge, timeout) via LocationEnginePlatforms.web().LocationEnginePlatforms: .android(), .iOS(), .web().android-sdk-opengl) for better stability and performance on older devices.preserveDrawingBuffer, antialias, and failIfMajorPerformanceCaveat from top-level MapOptions to canvasContextAttributes.on()/off()/once() event methods to handle v5's Subscription return type instead of map instance.customAttribution from MapOptions (now part of AttributionControl options in v5).actions/upload-artifact updated from v6 to v7 (#748).3.5.0 to 3.7.0 (#762).icon-text-fit-padding insets now use the correct style-spec order [top, right, bottom, left] — left and right were previously swapped (#792).text-font property handling on Android and iOS to correctly accept font stacks as string arrays instead of only expressions.textFont in SymbolManager to pass font names as a simple string array, resolving rendering issues on native platforms.terrarium/mapbox) for raster-dem tile sources on Android and iOS.Expressions.rgba/Expressions.rgb syntax.OfflineActivity from AndroidManifest.xml (#724).StreamSubscriptions in a module-level map so Dart's GC can't drop native events while a download is paused (#795).MLNOfflinePack instances so pause/resume/status operate on the live pack rather than reloading from storage (#795).onStyleLoaded callback to avoid race conditions (#719).styleimagemissing handling (#725).removeLayer and removeSource no longer throw when the layer/source doesn't exist.setGeoJsonSource returns early instead of crashing when the source doesn't exist.GeolocateControl now respects MyLocationTrackingMode and triggers programmatically.onUserLocationUpdated, web-specific tracking modes.['has', 'point_count'] filter to fix null property errors on unclustered points.Contributors: @MichaelNeufeld, @danieljosua1, @EyreFree, @skol-pro, @gabbopalma
Full Changelog: v0.25.0...v0.26.0
See the top-level CHANGELOG for full details.
initialCameraPosition is now nullable to support style-defined camera options (#769).LocationEnginePlatforms unnamed constructor is now private. Use .android(), .iOS(), .web(), or .defaultPlatform.LocationEngineAndroidProperties. All fields flattened into LocationEnginePlatforms with nullable platform-specific fields.MapLibrePlatform.easeCamera gained an optional named parameter CameraAnimationInterpolation? interpolation. Callers are unaffected, but subclasses that override easeCamera must add the new parameter to their signature (#789).takeSnapshot() (#726).featureTapsTriggersMapClick option to control whether feature taps also trigger map click callbacks (#729).setFeatureState, getFeatureState, removeFeatureState) (#718).LocationEnginePlatforms.android(), .iOS(), .web().toList().CameraAnimationInterpolation enum (linear, easeInOut, easeOut, fastOutLinearIn) and corresponding interpolation parameter on the camera#ease method channel (#789).No breaking changes for users. Your existing code works without modifications.
No breaking changes for users. Your existing code works without modifications.
The web platform was migrated internally to support WASM and Flutter 3.38.4+, but the public API remains unchanged.
Logo Customization
You can now control the MapLibre logo visibility and position on your maps:
MapLibreMap(
logoSettings: LogoSettings(
enabled: true, // Show the MapLibre logo!
position: LogoPosition.bottomLeft, // Or bottomRight, topLeft, topRight
),
)New Web Platform Methods
The web implementation now supports additional methods previously only available on mobile:
controller.getStyle() - Returns the current map style as a JSON stringcontroller.getSourceIds() - Returns a list of all source IDs in the current stylecontroller.getLayers() - Improved with safe null handlingExplicit Annotation Manager Initialization (#668)
Annotation methods now enforce explicit initialization with clear exceptions when the style is not loaded. This helps you catch issues early instead of getting silent failures or null dereferences:
add* methods before style load now fails fast with a clear ExceptionCamera Target Bounds (#8bcd74a)
Refactored cameraTargetBounds implementation for consistent behavior across platforms. You can now reliably constrain the camera to specific geographic bounds on both Android and iOS.
iOS Attribution Support
Source attribution strings are now properly displayed on iOS with clickable links. The implementation parses HTML attribution from source properties and creates native iOS attribution dialogs that open URLs when tapped.
WASM Compatible Web Platform (#687)
dart:js_util to modern dart:js_interop APIMapLibre Android SDK v12.3.0 (#690)
Example App Refactor
iOS
queryRenderedFeatures with empty layer list now returns all targets, matching Android behavior (#680)Web
setPaintProperty and setLayoutProperty now handle nullable JSAny values correctly (#12dfad2)jsify function to create JS arrays correctlyCross-Platform
lineDasharray and pattern properties reset to null in layer properties (#2b550ed)cameraTargetBounds for consistent behavior on Android and iOS (#8bcd74a)dependencies:
maplibre_gl: ^0.25.0That's it. No code changes needed.
A big thank you to everyone who contributed to this release!
@srmncnk, @albertmoravec, and all community members who reported issues and provided feedback.
Happy mapping! 🗺️ 💙
11.13.5 to 12.3.0 (#690).
4.12.0 to 5.3.2 for Node.js 24 compatibility (#676, #700).2.3.0 (#697, #698).8.13.2 (#695, #674).8.13.2 (#696, #689).actions/checkout updated from v5 to v6 (#672, #693).actions/upload-artifact updated from v4 to v6 (#688, #694).queryRenderedFeatures now returns all targets when supplying empty layers list on iOS, aligning behavior with Android (#680).lineDasharray and patterns reset to null in layer properties (#2b550ed).setLayerProperties and pattern images on web and Android (#9ce52a6).
cameraTargetBounds implementation on Android and iOS for consistent behavior (#8bcd74a).Full Changelog: v0.24.1...v0.25.0
See the top-level CHANGELOG for full details.
Added onCameraMove callback in the controller and in MapLibreMap class.
onCameraMove callback in the controller and in MapLibreMap class. (#643)4.7.1 version. (#660)A big thank you to everyone who contributed to this update!
Contributors: @andynewman10, @andrea689, @gabbopalma
Full Changelog: v0.24.0...v0.24.1
Note This release has breaking changes. We apologize for the quick change in 0.24.0: this version definitively stabilizes the signatures of feature in…
Note
This release has breaking changes.
We apologize for the quick change in 0.24.0: this version definitively stabilizes the signatures of feature interaction callbacks.
This release restores the feature id and makes the Annotation parameter nullable for all feature interaction callbacks (tap / drag / hover).
This unblocks interaction with style-layer features not managed by annotation managers (i.e. added via addLayer* / style APIs).
Warning
Tap: OnFeatureInteractionCallback → (Point<double> point, LatLng coordinates, String id, String layerId, Annotation? annotation).
Drag: OnFeatureDragCallback → (Point<double> point, LatLng origin, LatLng current, LatLng delta, String id, Annotation? annotation, DragEventType eventType).
Hover: OnFeatureHoverCallback → Point<double> point, LatLng coordinates, String id, Annotation? annotation, HoverEventType eventType).
Update existing listeners: The short‑lived 0.23.0-only signatures (without id) are removed.
annotation is null (unmanaged means sources/layers you add via style APIs like addGeoJsonSource + addSymbolLayer).Annotation object.In 0.23.0 the move to annotation objects inadvertently dropped interaction for unmanaged style features. Reintroducing id (and making annotation nullable) normalizes all three interaction paths without creating phantom annotation wrappers.
Before (0.23.0):
controller.onFeatureTapped.add((p, latLng, annotation, layerId) {
print(annotation.id);
});
After (>=0.24.0):
controller.onFeatureTapped.add((p, latLng, id, layerId, annotation) {
print('feature id=$id managed=${annotation != null}');
});
onMapClick (degenerate bbox + interactive layer filter) to surface features inserted via style APIs (unmanaged style-layer features) in onFeatureTapped (previously skipped; returned now with id, layerId and annotation = null) (#646).style.height = '100%' to the registered div (prevents occasional zero-height layout issues in flexible parents) (#641)Contributors: @andynewman10, @gabbopalma
Full Changelog: v0.23.0...v0.24.0
Caution USE 0.24.0 VERSION INSTEAD OF THIS ONE!
Caution
USE 0.24.0 VERSION INSTEAD OF THIS ONE!
This consolidated release delivers runtime style switching, hover interactions, heatmap & visibility features, native SDK updates, and broad naming / enum casing harmonization. It also fixes several interaction and stability issues across web and mobile.
If you are upgrading from <= 0.22.x:
Maplibre -> MapLibre) and enum / const lowerCamelCase migration.onFeatureTapped / onFeatureDrag now receive an Annotation instead of an id argument.onStyleLoaded due to stricter style readiness checks.A big thank you to everyone who contributed to this update!
Warning
onFeatureHover) (#614).LatLngBounds.contains convenience (#498).MaplibreStyles moved to main package) (#435, #413).annotationConsumeTapEvents).notifyListeners() after controller disposal (#621).Contributors: @AlexanderThiele, @mhernz, @TarekTolba1, @srmncnk, @itheamc, @kuhnroyal, @albertmoravec, @gabbopalma
Full Changelog: v0.22.0...v0.23.0
Note: This release has breaking changes.
This release aligns the plugin with the latest MapLibre Native (Android 11.9.0 / iOS 6.14.0), introduces runtime style switching APIs, hover interaction callbacks, and several annotation interaction improvements. It also contains a small breaking change for feature interaction callbacks.
A big thank you to everyone who contributed to this update!
onFeatureDrag / onFeatureTapped callback signatures now provide an Annotation annotation object instead of an id parameter. Update your handlers to remove the id argument and use annotation.id (or other annotation fields) as needed.setStyle…) without tearing down the map (#444, #603).onFeatureHover) for richer desktop/web UX (#614).onFeatureHover) (#614).annotationConsumeTapEvents).notifyListeners() after controller disposal (#621).Full Changelog: v0.22.0...v0.23.0
This PR addresses several crashes that occurred when attempting to add layers and sources that already exist.
This PR addresses several crashes that occurred when attempting to add
layers and sources that already exist.
The fix introduces appropriate guard statements and ensures that errors
are correctly propagated to the Flutter layer when necessary.
Previously, such issues would result in a crash. With this change, they
now raise a platform exception instead.
Co-authored-by: Alexander Thiele AlexanderThiele@users.noreply.github.com
await to all addLayer calls (#558).Unsupported operation error on web (#551).restructure folders with basic melos by @XanderD99 in #453
melos analyse exit code by @josxha in #471LatLngBounds by @ishafiul in #498Full Changelog: v0.20.0...v0.21.0
clearAmbientCache functionality (#502).contains functionality to LatLngBounds (#498).LocationEnginePlatforms properties for better device tracking on Android (#510).onFeatureTap returns the layerId (#475).maplibre_gl package to a subdirectory of the repository and add
melos to orchestrate all packages (#453).3.4.0 (Flutter SDK 3.22.0) (#542)A lot of files/classes have been renamed and moved around in this release. If you notice any build errors, please make sure to run flutter clean.
A lot of files/classes have been renamed and moved around in this release.
If you notice any build errors, please make sure to run flutter clean.
camel_case_types lint rule.MapLibreStyles to the main maplibre_gl package. You can now use themaplibre_gl_platform_interface as a dependency.plugins.flutter.io/maplibre_gl_* in all
packages.MaplibreMap and MaplibreMapController).Mapbox to MapLibre.1.9.0 (#460).Full Changelog: v0.19.0+2...v0.20.0
Nothing published for this version
Already since 0.17.0, developers do not need to adapt their Podfile for iOS apps anymore as it was previously described in the Readme. Developers who
Already since 0.17.0, developers do not need to adapt their Podfile for iOS apps anymore as it was previously described in the Readme. Developers who previously added these lines should remove them, since not removing these lines may cause a build failure on iOS. (This change actually already landed in 0.17.0, but it may not have been sufficiently clear that not removing these lines might break builds).
Full Changelog: 0.17.0...0.18.0
Repository transfer: The project repository was transferred to the MapLibre GitHub organization. More information at #221
maplibre_gl/mapbox_gl.dart was renamed to maplibre_gl/maplibre_gl.dart.
You can do a replace-all from import 'package:maplibre_gl/mapbox_gl.dart';
to import 'package:maplibre_gl/maplibre_gl.dart';useDelayedDisposal was removed since its now fixed
in #259useHybridCompositionOverride was removed since it was added in the following
fix: #203 and we
reverted
the fix and used another approach to fix the actual issue.myLocationRenderMode was changed from COMPASS to NORMAL
in #244, since the
previous default value of COMPASS implicitly enables displaying the location
on iOS, which could crash apps that didn't want to display the device
location. If you want to continue to use MyLocationRenderMode.COMPASS,
please explicitly specify it in the constructor like this:@override
Widget build() {
return MapLibreMap(
myLocationRenderMode: MyLocationRenderMode.COMPASS,
// ...
);
}
registerWith was removed from the MapboxMapsPlugin.java, since
there is no need for that.minSdkVersion was bumped to at least 21 now, since the native android
sdk constraint expect that.2.12.0 to 2.14.0
in maplibre_gl_platform_interface/pubspec.yaml.Note: This list only contains a subset of all contributions, notably excluding those that e.g. only affect the GitHub Actions CI or documentation. See the link at the end for a full changelog.
updateImageSource. by @CaviarChen
in #271Full Changelog: https://github.com/maplibre/flutter-maplibre-gl/compare/0.16.0...0.17.0
cherry-picked all commits from upstream up to [https://github.com/flutter-mapbox-gl/maps/commit/3496907955cd4b442e4eb905d67e8d46692174f1), including u
Your coding agent can read these notes before it upgrades. Set up the MCP server →