Skip to content

feat: experimental Kotlin Multiplatform support (clustering, library, heatmaps) - #1774

Draft
kikoso wants to merge 5 commits into
mainfrom
feat/experimental-kmp-clustering
Draft

feat: experimental Kotlin Multiplatform support (clustering, library, heatmaps)#1774
kikoso wants to merge 5 commits into
mainfrom
feat/experimental-kmp-clustering

Conversation

@kikoso

@kikoso kikoso commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

Experimental KMP migration of android-maps-utils, driven by the goal of exposing clustering (and friends) to the Kotlin Multiplatform module of android-maps-compose (googlemaps/android-maps-compose#927).

  • New maps-model module: common LatLng / CameraPosition. On Android they are actual typealiases to the Play Services classes, so the Android API surface and ABI are unchanged. On iOS they are value holders replicating GMS clamping/wrapping and equality semantics.
  • clustering: the full algorithm layer (quadtree, geometry, Mercator projection, all algorithms) moves to commonMain and compiles for Android + iosArm64/iosSimulatorArm64/iosX64. ClusterManager and the renderers stay Android-only in androidMain.
  • library: PolyUtil, SphericalUtil, MathUtil in commonMain; StreetView utilities, collections managers and the attribution initializer (codegen task ported to the KMP build) in androidMain.
  • heatmaps: WeightedLatLng, Gradient in commonMain — including a common ColorUtils reproducing Android/Skia RGB↔HSV exactly (verified by GradientTest's hardcoded Android color values); HeatmapTileProvider stays in androidMain.
  • JVM-only constructs replaced by multiplatform equivalents: expect/actual PlatformLock (ReentrantLock / NSRecursiveLock) for synchronized + ReentrantReadWriteLock, kotlin.math for Math.*, kotlin stdlib collections for java.util.
  • Java test suites converted to Kotlin (KMP compilations do not compile Java test sources). The PolyUtil/SphericalUtil/MathUtil suites moved to commonTest and run on iOS.
  • Publications are remapped to the repo's public artifactIds (android-maps-utils-clustering, android-maps-utils-core, …) so the KMP artifacts conflict-resolve as the same modules as the AARs on Maven Central.

Test plan

  • :clustering:testAndroidHostTest — 66 tests, :library:testAndroidHostTest — 60, :heatmaps:testAndroidHostTest — 24, all green (Robolectric pinned to sdk=28; it does not support targetSdk 37).
  • :library:iosSimulatorArm64Test — 36 geometry tests green on the iOS simulator.
  • :maps-utils:assembleRelease, :demo:assembleDebug, :data/:ui unit tests all pass against the converted modules.
  • Consumed end-to-end by android-maps-compose's maps-compose-multiplatform (PR chore(deps): bump android-maps-utils from 2.2.4 to 2.2.5 #927, CI green) via publishToMavenLocal.

Known gaps (why this is a draft)

  • Release publishing still bypasses PublishingConventionPlugin (vanniktech is AAR-only); needs a KotlinMultiplatform() variant. Jacoco, lintPublish (lint-checks), the amu_ resourcePrefix and consumer proguard rules also need KMP-aware re-wiring.
  • PreCachingAlgorithmDecorator stays Android-only (Executors-based; candidate for a coroutines rewrite).
  • External subclasses of NonHierarchicalDistanceBasedAlgorithm that did their own synchronized(mQuadTree) no longer synchronize with the internal lock.
  • data (GeoJSON/KML) is intentionally not migrated: it sits on org.json / XmlPullParser and would be a serialization rewrite, not a migration. ui stays Android by design.
  • AGP bumped 9.3.1 → 9.4.0 (AGP forbids mixing versions across composite builds with android-maps-compose).

Introduces a maps-model multiplatform module with common LatLng and
CameraPosition types (typealiased to the Play Services classes on
Android, plain value holders on iOS) and converts the clustering module
to Kotlin Multiplatform: the full algorithm layer (quadtree, geometry,
projection, all clustering algorithms) now lives in commonMain and
compiles for Android and iOS, while ClusterManager and the renderers
remain Android-only in androidMain.

JVM-only constructs in common code were replaced with multiplatform
equivalents: an expect/actual PlatformLock replaces synchronized blocks
and ReentrantReadWriteLock, java.util collections were swapped for
Kotlin stdlib ones, and Math.* calls for kotlin.math. The three
remaining Java test files were converted to Kotlin because KMP
compilations do not compile Java host-test sources.

Known gaps (prototype): publishing, jacoco, lint-checks and consumer
proguard rules are not yet wired for the KMP module layout.

Claude-Session: https://claude.ai/code/session_01225X6MnAqkyCF7Xones6WY
Apply maven-publish to maps-model and clustering so their multiplatform
publications can be published to mavenLocal for consumption by the
android-maps-compose KMP branch. Bump AGP 9.3.1 -> 9.4.0: AGP forbids
mixing versions across composite builds, and android-maps-compose is
already on 9.4.0.

Claude-Session: https://claude.ai/code/session_01225X6MnAqkyCF7Xones6WY
Publishing the KMP clustering module as com.google.maps.android:clustering
gave the same classes a second module identity next to the
android-maps-utils-clustering AAR on Maven Central, producing duplicate
class errors in apps that pull both (e.g. android-maps-compose's
maps-app). Remap the publication artifactIds to the repo's public
android-maps-utils-<module> scheme so both dependency paths
conflict-resolve to a single module.

Claude-Session: https://claude.ai/code/session_01225X6MnAqkyCF7Xones6WY
Converts the library module (PolyUtil, SphericalUtil, MathUtil in
commonMain; StreetView utilities, collections managers and the
attribution initializer in androidMain) and the heatmaps module
(WeightedLatLng, Gradient and shared constants in commonMain; the
Bitmap/Tile-based HeatmapTileProvider in androidMain) following the
pattern established by the clustering migration.

Gradient's android.graphics.Color usage is replaced by a common
ColorUtils that reproduces the Android/Skia RGB<->HSV conversions
exactly; GradientTest's hardcoded Android color values verify parity.
The AttributionId codegen task is ported into the KMP build and wired
into androidMain. Math.toRadians/toDegrees become common helpers.

The Java test suites (PolyUtilTest, SphericalUtilTest, MathUtilTest,
heatmaps UtilTest) are converted to Kotlin; the three math suites move
to commonTest and now also run on iOS (36 tests green on the iOS
simulator, 60 android host tests for library, 24 for heatmaps).
robolectric.properties pins sdk=28 for host tests as Robolectric does
not support targetSdk 37.

Claude-Session: https://claude.ai/code/session_01225X6MnAqkyCF7Xones6WY
The KMP Android library plugin does not create lintDebug/SARIF reporting
tasks, so :library:lintDebug no longer exists after the multiplatform
migration. Lint data, ui and demo instead; KMP-module lint reporting is
tracked as a known gap of the migration.
@github-advanced-security

Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

@googlemaps-bot

Copy link
Copy Markdown
Contributor

Code Coverage

Overall Project 50.69% 🍏

There is no coverage information present for the Files changed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants