Skip to content

About

Kotlin-first, MIT-licensed map view for Android, powered by OpenStreetMap. Familiar MapView API with markers, shapes, overlays and smooth camera animations, plus a Jetpack Compose OpenMap composable. No API keys, no Play Services.

Topics

Resources

Contributing

Stars

8 stars

Watchers

0 watching

Forks

Repository files navigation

CI Daily Tests Release API Documentation

OpenMapView

A modern, Kotlin-first MapView replacement for Android - powered by OpenStreetMap.

Installation

Add to your build.gradle.kts:

dependencies {
    implementation("de.afarber:openmapview:0.29.1")

    // Optional: the OpenMap composable for Jetpack Compose
    implementation("de.afarber:openmapview-compose:0.29.1")
}

Requirements: minSdk 23, compileSdk 37, Android Gradle Plugin 9.1 or newer and Kotlin 2.3 or newer.

The library is available on Maven Central. Alternative distribution via JitPack is also supported.

License

OpenMapView is MIT licensed, so you can use it in commercial apps. Its four runtime dependencies (androidx core-ktx, lifecycle-runtime-ktx, Compose ui-graphics and ktor-client-android) are all Apache 2.0. See the Dependency License Report for details.

Features

  • Drop-in compatible with the MapView API of the Maps SDK for Android (non-deprecated methods only)
  • Lightweight, pure Kotlin implementation without Play Services
  • OSM tiles via standard APIs (free, no API keys required)
  • Smooth camera animations with customizable durations and callbacks
  • Multiple overlay types: Markers, Polylines, Polygons, Circles, Ground Overlays, Tile Overlays, Info Windows
  • Multiple map types (see Map Types Guide)
  • Built-in zoom controls (+/- buttons) via UiSettings
  • External app integration (open in OsmAnd, Organic Maps and other map apps via geo: URI)
  • GeoJSON import support
  • Extensible marker, overlay, and gesture handling

API Documentation

Full API reference documentation is available at afarber.github.io/OpenMapView.

The documentation is generated from KDoc comments and redeployed whenever the library sources change on main.

Examples

Jetpack Compose (Kotlin) Views with XML (Java) Synopsis
Pan Pan Panning by touch and arrow buttons, flying to places and keeping the camera inside bounds
Zoom Zoom Smooth pinch zoom, zoom buttons and levels, zoom limits and why the camera moves
Markers Markers Colored markers with info windows, stepping through them and keeping them clear of a side panel with map padding
Polylines Polylines Lines, areas, a polygon with a hole and a geodesic flight, highlighted on tap through live shapes
Camera Camera Camera flights with durations, finish and cancel callbacks, stopping and interrupting them
Rotation Rotation A bus driving heading up like a navigation app, north up, turned by two fingers, a slider and the compass, with a flat marker
Clicks Clicks Tap and long-press coordinates, a circle following taps and markers dropped by long press
DraggableMarkers DraggableMarkers A route of draggable markers that the line follows while dragging, with drag events
Circles Circles Circles with radii in meters, selected by tap and resized live with a slider
Overlays Overlays Hiking, cycling and mountain bike tile overlays, turned on and off, with live transparency
GroundOverlays GroundOverlays Site plans placed by position or bounds, rotated and made transparent live
MapTypes MapTypes All 15 map types, their attribution and the notice for types that need an API key
Toolbar Toolbar Open a picked or long-pressed place in another map app, with a browser and QR code fallback
Tabs Tabs A map in a tab that keeps its camera, marker and route while other tabs are shown
GeoJson GeoJson Points, lines and areas loaded from a GeoJSON file with their styles, tapped for details and fitted into view
ScrollingPage ScrollingPage A static preview map that lets the page scroll over it and an interactive map inside a scrolling page

GeoJson example in Jetpack Compose

Documentation

Getting Started

With Jetpack Compose (Kotlin)

The optional openmapview-compose artifact provides the OpenMap composable. Its camera is kept in a CameraPositionState, which survives configuration changes and, when hoisted above the screen, also switching tabs:

@Composable
fun MapScreen() {
    val cameraPositionState = rememberCameraPositionState {
        position = CameraPosition(LatLng(51.4661, 7.2491), 14f)
    }

    OpenMap(
        modifier = Modifier.fillMaxSize(),
        cameraPositionState = cameraPositionState,
        properties = MapProperties(mapType = MapType.CARTO_LIGHT, minZoomPreference = 10f),
        uiSettings = MapUiSettings(zoomControlsEnabled = true),
        onMapLongClick = { latLng -> /* ... */ },
    ) {
        // Dragging updates the state; setting state.position moves the marker
        val markerState = rememberMarkerState(LatLng(51.4661, 7.2491))
        Marker(state = markerState, title = "Bochum City Center", draggable = true)

        // Shapes are replaced when a parameter changes, so this circle follows the marker
        Circle(center = markerState.position, radius = 300f, fillColor = Color.Blue.copy(alpha = 0.2f))
        Polyline(points = route, strokeColor = Color.Red, clickable = true, onClick = { /* ... */ })
    }

    // Move the camera by setting cameraPositionState.position, or animate it
    // from a coroutine: cameraPositionState.animate(CameraUpdateFactory.zoomIn())
}

Content composables: Marker, Polyline, Polygon, Circle, GroundOverlay and TileOverlay. Their parameters match the model classes of the same names. MarkerState.showInfoWindow() opens a marker's info window, and MarkerInfoWindow and MarkerInfoWindowContent draw it with your own composables. MarkerComposable draws a marker icon from a composable, and Clustering groups many markers into clusters. OpenMap takes the map type, zoom limits, camera bounds and the my-location layer as MapProperties, the controls and gestures as MapUiSettings, and onMapClick, onMapLongClick and onMapLoaded callbacks. ScaleBar and DisappearingScaleBar show the map scale next to it. It sets the map's camera, marker and shape listeners itself, so use the composables' state and callbacks instead.

With XML Layouts (Java)

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Ready right away: no getMapAsync() and no lifecycle forwarding
        OpenMapView mapView = findViewById(R.id.mapView);
        mapView.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(51.4661, 7.2491), 14f));
        mapView.addMarker(new MarkerOptions()
                .position(new LatLng(51.4661, 7.2491))
                .title("Bochum City Center"));
    }
}

About

Kotlin-first, MIT-licensed map view for Android, powered by OpenStreetMap. Familiar MapView API with markers, shapes, overlays and smooth camera animations, plus a Jetpack Compose OpenMap composable. No API keys, no Play Services.

Topics

Resources

Contributing

Stars

8 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages