A modern, Kotlin-first MapView replacement for Android - powered by OpenStreetMap.
Add to your build.gradle.kts:
dependencies {
implementation("de.afarber:openmapview:0.14.2")
}Requirements: minSdk 23, compileSdk 37 and Android Gradle Plugin 9.1 or newer (since 0.14.0, because androidx.core 1.19 and Compose UI 1.12 require them). Since 0.14.1 the app also needs Kotlin 2.3 or newer, because the library is built with Kotlin 2.4. Projects still on compileSdk 36 or AGP 8 can stay on 0.13.3.
The library is available on Maven Central. Alternative distribution via JitPack is also supported.
OpenMapView is MIT licensed, so you can use it in commercial apps. Its five runtime dependencies (androidx core-ktx, lifecycle-runtime-ktx, Compose ui-graphics, ktor-client-android and DiskLruCache) are all Apache 2.0. See the Dependency License Report for details.
- Drop-in compatible with Google
MapView(non-deprecated methods only) - Lightweight, pure Kotlin implementation with zero Google dependencies
- 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 Google Maps, OsmAnd, etc. via geo: URI)
- GeoJSON import support
- Extensible marker, overlay, and gesture handling
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.
Explore the example applications to see OpenMapView in action:
- Example01Pan - Basic map panning with touch gestures
- Example02Zoom - Built-in zoom controls (+/- buttons) and zoom level display
- Example03Markers - Marker overlays with custom colors and info windows
- Example04Polylines - Polylines, polygons, and polygons with holes (donut shapes)
- Example05Camera - Camera animations with callbacks, custom durations, and built-in zoom controls
- Example06Clicks - Map click and long-click listeners with coordinate display
- Example07DraggableMarkers - Draggable markers with drag event listeners
- Example08Circles - Circles with radius, styling, z-index ordering, and click listeners
- Example09Overlays - Tile overlays with transparency control (OpenSeaMap, Railways, Trails, Snow)
- Example10GroundOverlays - Ground overlays with position/bounds modes, rotation, and transparency
- Example11MapTypes - Switching between all 15 map types (OSM, CyclOSM, Thunderforest, CARTO, Stamen and more)
- Example12Toolbar - Open location in external map apps via geo: URI with OpenStreetMap browser fallback
- Public API Compatibility - Google MapView API implementation status and compatibility matrix
- Architecture - Architectural design and comparison with Google Maps SDK
- Replacing Google Maps - Migration guide for switching from Google Maps SDK to OpenMapView
- Map Types - Available map types and tile sources
- Map Toolbar - External map app integration using geo: URIs with browser fallback
- Performance - Performance optimization and benchmarking
- Contributing Guide - Code quality requirements, formatting, git hooks, and PR process
- Lifecycle Management - How OpenMapView handles Android lifecycle events
- Publishing Guide - Publishing to Maven Central and JitPack
- GitHub Workflows - CI/CD pipeline and workflow architecture
- Unit Testing - JVM unit tests with Robolectric for Android framework APIs
- Instrumented Testing - On-device (phone and auto) testing with Android emulator
@Composable
fun MapViewScreen() {
val lifecycleOwner = androidx.lifecycle.compose.LocalLifecycleOwner.current
AndroidView(
factory = { context ->
OpenMapView(context).apply {
// Register lifecycle observer for proper cleanup
lifecycleOwner.lifecycle.addObserver(this)
setCenter(LatLng(51.4661, 7.2491))
setZoom(14.0f)
// Add markers - Kotlin style (direct instantiation)
addMarker(Marker(
position = LatLng(51.4661, 7.2491),
title = "Bochum City Center"
))
// Or Google Maps API style (builder pattern)
addMarker(
MarkerOptions()
.position(LatLng(51.4700, 7.2550))
.title("North Location")
.draggable(true)
)
}
},
modifier = Modifier.fillMaxSize()
)
}class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val mapView = findViewById<OpenMapView>(R.id.mapView)
mapView.setZoom(14.0f)
mapView.setCenter(LatLng(51.4661, 7.2491))
}
}