Kotlin Quickstart
Android native maps via MapLibre Native Android.
Install
kotlin
// app/build.gradle.kts
dependencies {
implementation("org.maplibre.gl:android-sdk:11.0.0")
}AndroidManifest.xml
Add Internet permission. Register your package name in the dashboard against the public key.
xml
<uses-permission android:name="android.permission.INTERNET" />Render a map
kotlin
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import org.maplibre.android.MapLibre
import org.maplibre.android.camera.CameraPosition
import org.maplibre.android.geometry.LatLng
import org.maplibre.android.maps.MapView
import org.maplibre.android.maps.Style
class MapActivity : AppCompatActivity() {
private lateinit var mapView: MapView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
MapLibre.getInstance(this)
setContentView(R.layout.activity_map)
val key = BuildConfig.MFD_PUBLIC_KEY
val styleUrl = "https://api.mapsfordevs.com/styles/standard.json?key=$key"
mapView = findViewById(R.id.mapView)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync { map ->
map.setStyle(styleUrl) { /* style loaded */ }
map.cameraPosition = CameraPosition.Builder()
.target(LatLng(-26.20, 28.04))
.zoom(11.0)
.build()
}
}
override fun onStart() { super.onStart(); mapView.onStart() }
override fun onResume() { super.onResume(); mapView.onResume() }
override fun onPause() { super.onPause(); mapView.onPause() }
override fun onStop() { super.onStop(); mapView.onStop() }
override fun onDestroy(){ super.onDestroy(); mapView.onDestroy() }
override fun onLowMemory() { super.onLowMemory(); mapView.onLowMemory() }
}Geocoding (kotlinx.serialization + ktor)
kotlin
// build.gradle.kts
// implementation("io.ktor:ktor-client-core:2.3.10")
// implementation("io.ktor:ktor-client-cio:2.3.10")
// implementation("io.ktor:ktor-client-content-negotiation:2.3.10")
// implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.10")
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.engine.cio.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.request.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.Serializable
@Serializable data class GeocodeItem(
val lat: Double, val lng: Double, val label: String,
val confidence: Double, val type: String
)
@Serializable data class GeocodeResponse(
val ok: Boolean, val items: List<GeocodeItem>? = null, val error: String? = null
)
class MapsForDevsClient(private val apiKey: String) {
private val http = HttpClient(CIO) {
install(ContentNegotiation) { json() }
}
suspend fun geocode(query: String, country: String? = null, limit: Int = 5): List<GeocodeItem> {
val resp: GeocodeResponse = http.get("https://api.mapsfordevs.com/geocode/forward") {
header("Authorization", "Bearer $apiKey")
url.parameters.append("q", query)
url.parameters.append("limit", limit.toString())
country?.let { url.parameters.append("country", it) }
}.body()
if (!resp.ok) throw RuntimeException(resp.error ?: "mfd error")
return resp.items ?: emptyList()
}
}Compose helper
kotlin
import androidx.compose.runtime.*
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.viewinterop.AndroidView
@Composable
fun MapLibreMap(styleUrl: String) {
val context = LocalContext.current
AndroidView(factory = {
MapLibre.getInstance(it)
MapView(it).apply {
onCreate(null)
getMapAsync { map -> map.setStyle(styleUrl) }
}
})
}