This guide outlines the major architectural changes, breaking changes, and source migrations required when upgrading the Google Maps Android Utility Library from v4.x to the new Kotlin-rewritten v5.x release.
To improve build times and allow modern modular applications to import only what they need, the library has been split from a monolithic structure into several submodules:
android-maps-utils-core(:library): The base utility code, includingPolyUtil,SphericalUtil,MathUtil, and base collection managers (MarkerManager,PolygonManager,PolylineManager, etc.).android-maps-utils-data(:data): KML and GeoJSON parsing and rendering.android-maps-utils-clustering(:clustering): High-performance marker clustering and algorithm utilities.android-maps-utils-heatmaps(:heatmaps): Heatmap overlay tile providers.android-maps-utils-ui(:ui): Custom markers, bubble drawables, and rotation layouts.
If your project uses all utilities, you can import the aggregator artifact directly:
# gradle/libs.versions.toml
[versions]
androidMapsUtils = "5.0.0" # x-release-please-version
[libraries]
android-maps-utils = { group = "com.google.maps.android", name = "android-maps-utils", version.ref = "androidMapsUtils" }This aggregator dynamically and transitively pulls all individual submodules. Alternatively, you can choose to import only the specific submodules your app requires (e.g., android-maps-utils-core and android-maps-utils-clustering).
Many core classes have been rewritten in idiomatic Kotlin. Because Kotlin does not synthesize property getter/setter methods for Kotlin-defined functions, Kotlin callers must migrate from calling traditional Java-style getter/setter methods to accessing properties directly.
The ClusterItem interface is now written in Kotlin. Custom cluster item classes (such as data classes) can now directly override the properties in the constructor, eliminating verbose method overrides.
data class MyItem(
val latLng: LatLng,
val myTitle: String?,
val mySnippet: String?,
val myZIndex: Float?
) : ClusterItem {
override fun getPosition() = latLng
override fun getTitle() = myTitle
override fun getSnippet() = mySnippet
override fun getZIndex() = myZIndex
}data class MyItem(
override val position: LatLng,
override val title: String?,
override val snippet: String?,
override val zIndex: Float?
) : ClusterItemThe abstract method getFeatures() in Layer has been migrated to a read-only property features.
- Kotlin callers: Access
layer.featuresinstead oflayer.getFeatures(). - Java callers: Seamlessly continue calling
layer.getFeatures()(supported via Kotlin JVM bytecode generation).
Styles on GeoJsonFeature have been converted to first-class properties:
- Kotlin callers: Use
.pointStyle,.lineStringStyle, and.polygonStyledirectly instead of calling.getPointStyle()/.setPointStyle(...).
// Before
feature.setLineStringStyle(GeoJsonLineStringStyle().apply {
setColor(Color.RED)
})
// After
feature.lineStringStyle = GeoJsonLineStringStyle().apply {
color = Color.RED
}The Layer.OnFeatureClickListener interface has been converted to a Kotlin fun interface (functional interface):
public fun interface OnFeatureClickListener {
public fun onFeatureClick(feature: Feature)
}This enables Kotlin developers to seamlessly pass clean click lambdas using standard SAM conversion:
geoJsonLayer.setOnFeatureClickListener { feature ->
Toast.makeText(context, "Clicked feature: ${feature.id}", Toast.LENGTH_SHORT).show()
}Unlike the previous version, this SAM conversion is fully supported for native Kotlin callers without requiring anonymous object syntax (object : Layer.OnFeatureClickListener { ... }).