Skip to content

Present outside Compose UI

MaplibreMap provides the map’s Compose UI integration. When another framework owns the UI, such as Android Auto, CarPlay, UIKit, SwiftUI, or React, use a platform presentation to reuse the same map state, camera operations, and declarative styles.

Create a MapState with MapRuntime.createMapState and pass it to a presentation. Your application supplies the host, manages its lifecycle, and forwards recognized gestures through the map’s input methods. Compose UI dependencies are still required, but a Compose UI hierarchy is not.

AndroidMapPresentation draws into an Android Surface, such as one supplied by Android Auto. Connect the presentation to the host’s lifecycle and surface callbacks:

SurfaceMapHost.kt
/** Your code owns the MapState and each Surface. Call these methods on the main thread. */
class SurfaceMapHost(context: Context, state: MapState, lifecycle: Lifecycle) : AutoCloseable {
val presentation = AndroidMapPresentation(context, state, lifecycle)
private var binding: AndroidMapPresentation.SurfaceBinding? = null
fun onSurfaceAvailable(surface: Surface, width: Int, height: Int, density: Float) {
binding = presentation.attachSurface(surface, width, height, density)
}
fun onSurfaceChanged(width: Int, height: Int, density: Float) {
binding?.update(width, height, density)
}
fun onSurfaceDestroyed() {
binding?.close()
binding = null
}
fun onConfigurationChanged(configuration: Configuration) {
presentation.updateConfiguration(configuration)
}
override fun close() {
presentation.close()
}
}

The Android Auto demo shows a complete car-app integration. See AndroidMapPresentation for configuration, surface ownership, and lifecycle contracts.

AppleMapPresentation presents the map, and MaplibreMapView supplies a UIKit view that manages the Metal layer and its layout:

UIKitMapHost.kt
/** The caller owns the MapState. Create and use this host on the main thread. */
class UIKitMapHost(state: MapState) : AutoCloseable {
val presentation = AppleMapPresentation(state, isActive = false)
val view: UIView = MaplibreMapView(presentation)
fun onSceneActivationChanged(active: Boolean) {
presentation.isActive = active
}
override fun close() {
view.removeFromSuperview()
presentation.close()
}
}

Add the view to a UIKit or CarPlay view hierarchy, or return it from SwiftUI’s UIViewRepresentable.makeUIView. Forward activation from the scene hosting the map; CarPlay has a separate scene from the phone’s UI. The CarPlay demo shows the scene integration. See MaplibreMapView and AppleMapPresentation for ownership, configuration, and lifecycle contracts.

For hosts that already manage a Metal layer, use AppleMapPresentation.attachLayer directly. This is the same attachment API used by MaplibreMapView.

WebMapPresentation presents a map in an HTML element for Kobweb, Compose HTML, or Kotlin React. Give the element a CSS width and height:

WebMapHost.kt
/** The caller owns the MapState and gives the container a CSS width and height. */
class WebMapHost(state: MapState, container: HTMLElement) : AutoCloseable {
val presentation = WebMapPresentation(state)
private val binding = presentation.attachContainer(container)
override fun close() {
binding.close()
presentation.close()
}
}

Create the host when your framework mounts the element, and close it before the element is removed. See WebMapPresentation for configuration, container ownership, and lifecycle contracts. The default worker is embedded in the library and uses a Blob URL. If your Content Security Policy excludes blob workers, serve maplibre-gl/worker.mjs from the library’s JS KLIB and pass its URL to configureMapLibreWorker before creating maps. Use the worker from the same Compose release so it includes the matching engine patches.