Yatmo Android SDK
A Kotlin library that puts the Yatmo map in an Activity, a Fragment or a Compose screen, with a coroutine client for the neighbourhood data. Built on MapLibre Android, no Google Maps key needed.
Requirements
minSdk24 (Android 7), Kotlin 1.9 or later, AndroidX.- MapLibre Android 11.x and
kotlinx-coroutines-android(transitive dependencies). - Your frontend key with your application id registered as an app id.
Install
// settings.gradle.kts: JitPack builds the library from the GitHub release tag
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}
// app/build.gradle.kts
dependencies {
implementation("com.github.Yatmo:yatmo-sdk-android:v1.0.0")
}
Source and releases: github.com/yatmo/yatmo-sdk-android.
Only the INTERNET permission is needed; the library declares it in its manifest.
Configure
One Yatmo instance per app, created in your Application class or your dependency injection graph:
import com.yatmo.sdk.*
class MyApp : Application() {
lateinit var yatmo: Yatmo
override fun onCreate() {
super.onCreate()
yatmo = Yatmo(this, YatmoConfiguration(
licenseKey = "YOUR_FRONTEND_KEY",
country = Country.BE,
language = Language.FR
))
}
}
The app id is read from context.packageName, which is your applicationId including any debug suffix. The constructor also initialises MapLibre (MapLibre.getInstance), so create it before inflating any map.
The map (XML / Activity)
<com.yatmo.sdk.YatmoMapView
android:id="@+id/yatmoMap"
android:layout_width="match_parent"
android:layout_height="320dp" />
class ListingActivity : AppCompatActivity() {
private lateinit var map: YatmoMapView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_listing)
map = findViewById(R.id.yatmoMap)
map.onCreate(savedInstanceState)
map.attach((application as MyApp).yatmo, style = YatmoMapStyle.LIBERTY)
map.showProperty(latitude = 50.8520525, longitude = 4.3442926, zoom = 15.0)
map.showIsochrones(TravelMode.WALKING) // optional
map.onPoiSelected = { poi -> Log.d("Yatmo", "${poi.name} (${poi.type})") }
}
// MapLibre needs the lifecycle forwarded
override fun onStart() { super.onStart(); map.onStart() }
override fun onResume() { super.onResume(); map.onResume() }
override fun onPause() { map.onPause(); super.onPause() }
override fun onStop() { map.onStop(); super.onStop() }
override fun onLowMemory() { super.onLowMemory(); map.onLowMemory() }
override fun onDestroy() { map.onDestroy(); super.onDestroy() }
override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState); map.onSaveInstanceState(outState) }
}
The underlying MapLibre MapView is available as map.mapView, and the MapLibreMap through map.getMapAsync { }.
Jetpack Compose
@Composable
fun ListingMap(yatmo: Yatmo) {
YatmoMap(
yatmo = yatmo,
latitude = 50.8520525,
longitude = 4.3442926,
zoom = 15.0,
style = YatmoMapStyle.LIBERTY,
isochrones = TravelMode.WALKING,
onPoiSelected = { poi -> /* show a bottom sheet */ },
modifier = Modifier.fillMaxWidth().height(320.dp)
)
}
YatmoMap is an AndroidView wrapper that forwards the lifecycle for you.
Map options
| Name | In | Type | Description |
|---|---|---|---|
| style | YatmoMapStyle |
LIBERTY, BASIC, BRIGHT, THREE_D, POSITRON, DARK, LIBERTY_STONEHEDGE.
Default: LIBERTY. |
|
| showProperty(latitude, longitude, zoom) | method | Centres the map and drops the property pin. | |
| poiTypeIds | List<Long>? |
Restrict the POIs to some categories, ids from client.simplifiedCategories().
Default: null (all). |
|
| poiIconSizeDp | Int |
Marker size in dp (24 or 32).
Default: 24. |
|
| showIsochrones(mode) / hideIsochrones() | method |
5 / 10 / 20 minute areas for WALKING, BICYCLING, DRIVING or TRANSIT.
|
|
| fitIsochrones / isochronePaddingDp | Boolean / Int |
Like the web plugin: once the isochrones are drawn the camera fits the largest area, and hideIsochrones() restores the previous camera.
Default: true / 40. |
|
| minZoomForPois | Double |
No POI request below this zoom.
Default: 13.0. |
|
| onPoiSelected | (YatmoPoi) -> Unit | Marker tapped. The SDK draws no popup. | |
| onError | (Throwable) -> Unit | Network or licence errors while loading POIs or isochrones. |
Data: YatmoClient
Every method is a suspend function running on Dispatchers.IO:
lifecycleScope.launch {
val client = yatmo.client
val summary = client.summary(50.8520525, 4.3442926)
summary.categories.forEach { category ->
Log.d("Yatmo", category.label)
category.subCategories.forEach { Log.d("Yatmo", " ${it.label}: ${it.places.size}") }
}
val text = client.summaryText(50.8520525, 4.3442926) // generated paragraphs
val scores = client.scores(50.8520525, 4.3442926) // 0 to 10 per category
val enrichment = client.enrichment(50.8520525, 4.3442926) // nearest place per category, 4 travel modes
val places = client.geocode("Rue Neuve", 50.85, 4.35) // address autocomplete
val pois = client.points(southWest = LatLng(50.848, 4.338), northEast = LatLng(50.856, 4.350))
val isochrones = client.isochrones(TravelMode.WALKING, 50.8520525, 4.3442926)
val groups = client.simplifiedCategories()
}
Errors are thrown as YatmoException with the HTTP status and the server message. Response shapes: Summary, Enrichment, Points, Isochrone, Geolocation.
WebView fallback
val web = YatmoWebView(this)
web.load(yatmo, YatmoWebViewOptions(latitude = 50.8520525, longitude = 4.3442926, mode = "overlay", zoom = 15, accentColor = "#428BFF"))
container.addView(web)
It enables JavaScript and DOM storage and loads the iframe plugin page.
Troubleshooting
- 403 on every call: your
applicationId(with its debug suffix) is not registered. See Mobile authentication. - Crash "MapLibre.getInstance() must be called": create the
Yatmoinstance before inflating the layout. - Blank map after rotation: forward
onSaveInstanceStateand the other lifecycle methods, or use the Compose wrapper. - R8 / ProGuard: the library ships its consumer rules; nothing to add.
Related: iOS SDK · Bring your own map · Overview.