While migrating Ferrostar to org.maplibre.compose here: stadiamaps/ferrostar#853 I ran into a gap for navigation use cases.
Use case
In navigation, the displayed user location is often not raw GPS.
Instead, apps typically use a preferred location:
- snapped-to-route while the user is still on-route
- raw location when off-route
This avoids the puck jumping around because of GPS noise.
How Ferrostar handles this on iOS
On iOS with MapLibreSwiftUI, Ferrostar already does this successfully:
NavigationState.preferredUserLocation returns snapped or raw location depending on route state
- NavigationMapView feeds that into a StaticLocationManager
- MapLibre native tracking (followWithCourse) uses that location source directly
So on iOS:
- native puck
- native follow camera
- snapped location
all use the same native pipeline.
Problem on Android Compose
maplibre-compose already has:
- LocationProvider
- UserLocationState
- rememberUserLocationState
- LocationPuck
- LocationTrackingEffect
But there does not seem to be a way to let the map’s native tracking / native puck use an app-provided location source.
Because of that, libraries like Ferrostar currently have to:
- compute a snapped location themselves
- move the camera manually
- render a custom puck separately
That works to some extend, but it is not as robust as the iOS approach.
What we would like
A way to provide a custom tracked location source to MaplibreMap, so native tracking and native puck rendering can use it.
Conceptually something like:
val preferredLocationState = rememberUserLocationState(preferredLocationProvider)
MaplibreMap(
baseStyle = baseStyle,
cameraState = cameraState,
trackedLocationState = preferredLocationState,
trackingMode = TrackingMode.FollowWithCourse,
locationPuck = LocationPuck.Default,
)
Why this matters
For navigation, this would allow:
- app computes preferred location
- snapped on-route
- raw off-route
- map consumes that source directly
- native puck + native follow camera stay in sync
This is preferable to rendering a separate custom puck.
KMP angle
Since maplibre-compose is a KMP library, this seems like a good fit for:
- a shared common API
- platform-specific implementations underneath
At least Android and iOS seem relevant here.
iOS in particular looks like a natural fit, because this model already exists conceptually there via native tracking + app-provided location source.
Native platform hooks already seem to exist
From what I can tell, this may only require exposing existing native SDK capability cleanly in maplibre-compose.
- On iOS,
MLNMapView already has a locationManager property. Ferrostar uses this with a StaticLocationManager to feed a preferred navigation location into the native puck / native tracking pipeline.
- On Android, this appears to map to
LocationComponent, which already supports custom location input via a custom LocationEngine, and also manual updates via forceLocationUpdate(...) when default engine management is disabled.
So the missing piece seems to be mainly at the maplibre-compose API layer: exposing these native tracked-location hooks in a multiplatform-friendly way.
Backward compatibility
This seems possible to add in a fully backward-compatible way.
The existing Compose-based APIs could remain unchanged, especially:
- LocationPuck
- LocationTrackingEffect
- CameraState
A native tracked-location pipeline could be introduced as an additional opt-in path for navigation use cases, while existing apps continue to use the current Compose-based location puck and camera-tracking approach.
That would allow:
- existing apps to keep using LocationPuck as they do today
- navigation apps to opt into a native puck + native follow mode driven by an app-provided location source
The important part is that this would be additive, not a replacement of the current APIs.
Environment
- org.maplibre.compose:maplibre-compose:0.12.1
- Android
- navigation / follow-camera UI
- app-computed snapped route location
I will try to work on a PR for this soon, since this would significantly improve the Ferrostar navigation integration.
While migrating Ferrostar to org.maplibre.compose here: stadiamaps/ferrostar#853 I ran into a gap for navigation use cases.
Use case
In navigation, the displayed user location is often not raw GPS.
Instead, apps typically use a preferred location:
This avoids the puck jumping around because of GPS noise.
How Ferrostar handles this on iOS
On iOS with MapLibreSwiftUI, Ferrostar already does this successfully:
NavigationState.preferredUserLocationreturns snapped or raw location depending on route stateSo on iOS:
all use the same native pipeline.
Problem on Android Compose
maplibre-compose already has:
But there does not seem to be a way to let the map’s native tracking / native puck use an app-provided location source.
Because of that, libraries like Ferrostar currently have to:
That works to some extend, but it is not as robust as the iOS approach.
What we would like
A way to provide a custom tracked location source to MaplibreMap, so native tracking and native puck rendering can use it.
Conceptually something like:
Why this matters
For navigation, this would allow:
This is preferable to rendering a separate custom puck.
KMP angle
Since maplibre-compose is a KMP library, this seems like a good fit for:
At least Android and iOS seem relevant here.
iOS in particular looks like a natural fit, because this model already exists conceptually there via native tracking + app-provided location source.
Native platform hooks already seem to exist
From what I can tell, this may only require exposing existing native SDK capability cleanly in
maplibre-compose.MLNMapViewalready has alocationManagerproperty. Ferrostar uses this with aStaticLocationManagerto feed a preferred navigation location into the native puck / native tracking pipeline.LocationComponent, which already supports custom location input via a customLocationEngine, and also manual updates viaforceLocationUpdate(...)when default engine management is disabled.So the missing piece seems to be mainly at the
maplibre-composeAPI layer: exposing these native tracked-location hooks in a multiplatform-friendly way.Backward compatibility
This seems possible to add in a fully backward-compatible way.
The existing Compose-based APIs could remain unchanged, especially:
A native tracked-location pipeline could be introduced as an additional opt-in path for navigation use cases, while existing apps continue to use the current Compose-based location puck and camera-tracking approach.
That would allow:
The important part is that this would be additive, not a replacement of the current APIs.
Environment
I will try to work on a PR for this soon, since this would significantly improve the Ferrostar navigation integration.