Skip to content
This site is a preview of the main branch. The published documentation is at maplibre.org.

Show the user's location

Draw the user’s location as a dot on the map and center the camera on each location update:

App.kt
val locationState =
rememberLocationState(
provider = rememberDefaultLocationProvider(),
headingProvider = rememberDefaultHeadingProvider(),
)
val mapState = rememberMapState {
LocationIndicatorLayer(id = "user", locationState = locationState)
}
LocationTrackingEffect(locationState = locationState) {
if (previousLocation == null) {
// First location: zoom in on the user.
mapState.animateCamera(CameraUpdate(center = currentLocation.position, zoom = 15.0))
} else {
updateCamera(mapState)
}
}
MaplibreMap(state = mapState)

The dot requires location access. Request location permission when the user chooses to display their location.

The example uses these APIs:

  • A LocationProvider reads the device’s location. rememberDefaultLocationProvider returns the provider for the current platform.
  • rememberLocationState collects location updates from the provider while the screen is visible and stores the latest one in LocationState.lastLocation.
  • LocationIndicatorLayer draws a dot at that location, with a circle that shows its accuracy. It draws nothing until the provider reports a location.
  • LocationTrackingEffect runs its block each time the location or its direction changes. The example sets the zoom for the first location, then uses updateCamera to center the camera on each update. By default, updateCamera also rotates the map to the user’s movement direction or the device’s heading, when available. Pass updateBearing = BearingUpdate.Ignore to preserve the camera’s bearing.

An optional heading provider supplies the device’s compass direction, which the dot displays when available. rememberDefaultHeadingProvider reads the compass on Android and iOS, and supplies no heading on other platforms.

Pass enabled = false to LocationTrackingEffect to stop moving the camera. Use camera gesture events to disable tracking when the user pans the map.

By default, rememberLocationState requests high accuracy and at most one location update per second. To reduce battery use, configure lower accuracy or less frequent updates with LocationRequest. HeadingRequest configures heading updates:

App.kt
val locationState =
rememberLocationState(
provider = provider,
request =
LocationRequest {
accuracy = LocationAccuracy.Balanced
minimumInterval = 5.seconds
},
headingProvider = headingProvider,
headingRequest = HeadingRequest { minimumInterval = 2.seconds },
)

Omitted parameters use their default values.

The library does not request location permission automatically. Call LocationState.requestPermission in response to a user action, such as pressing a button to display their location:

App.kt
if (locationState.permission !is LocationPermission.Granted) {
Button(onClick = locationState::requestPermission) { Text("Show my location") }
}

The platform shows its permission dialog.

If the user denies access, use the properties of LocationPermission.NotGranted to determine whether to request permission again or open system settings:

  • shouldShowRationale is true: explain why your app needs the location, then request permission again. Only Android sets this property.
  • canRequest is true or null: you can request permission again.
  • canRequest is false: only the system settings can change the permission. rememberSystemSettingsLauncher opens them on the platforms that support this action.
App.kt
val settings = rememberSystemSettingsLauncher()
val permission = locationState.permission
if (permission is LocationPermission.NotGranted) {
when {
permission.shouldShowRationale -> {
Text("Your location helps you find places nearby.")
Button(onClick = locationState::requestPermission) { Text("Continue") }
}
permission.canRequest != false ->
Button(onClick = locationState::requestPermission) { Text("Show my location") }
settings.canOpenApplicationSettings ->
Button(onClick = { settings.openApplicationSettings() }) { Text("Open settings") }
}
}

Use LocationState.availability to check for missing or misconfigured location support. LocationState.status reports interruptions to location updates, such as disabled location services. Display a message and call LocationState.retry when the user chooses to retry:

App.kt
val settings = rememberSystemSettingsLauncher()
if (locationState.availability != LocationBackendAvailability.Available) {
Text("Location is not available on this device.")
}
val status = locationState.status
if (status is LocationTrackingStatus.Unavailable) {
if (status.reason == LocationUnavailableReason.ServicesDisabled) {
Text("Turn on location services to see your position.")
if (settings.canOpenLocationServicesSettings) {
Button(onClick = { settings.openLocationServicesSettings() }) { Text("Open settings") }
}
} else {
Text("Your location is not available right now.")
}
Button(onClick = locationState::retry) { Text("Try again") }
}

When availability is LocationBackendAvailability.Misconfigured, its cause describes the configuration error.

The JVM desktop runtimes in Platform setup include location support for their operating system.

Declare the location permissions in your app’s manifest:

AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

The default providers use Android’s built-in location service. To use Google’s fused location and heading instead, add the optional Google Play services runtime:

build.gradle.kts
androidMain.dependencies {
implementation("org.maplibre.compose:location-runtime-gms:0.20.0")
}

On devices without Google Play services, the default providers still use the built-in service.

For Huawei devices, location-runtime-hms provides fused location through Huawei Mobile Services. It needs Huawei’s Maven repository, https://developer.huawei.com/repo/, and the HMS Core setup.

Add a location usage description to your app’s Info.plist. iOS shows this text in the permission dialog:

Info.plist
<key>NSLocationWhenInUseUsageDescription</key>
<string>Shows your position on the map.</string>

Browsers provide location only on pages served over HTTPS or from localhost. See secure contexts.

For both JVM and native macOS apps, add a location usage description to the app bundle’s Info.plist:

Info.plist
<key>NSLocationUsageDescription</key>
<string>Shows your position on the map.</string>

Apps using App Sandbox or Hardened Runtime also need the location entitlement.

For JVM apps packaged with Compose Desktop, set the usage description in nativeDistributions { macOS { infoPlist { extraKeysRawXml = ... } } }. Configure entitlementsFile and runtimeEntitlementsFile if the location entitlement is required.

Location uses the XDG Location portal. Without the portal, availability is Unsupported.