Skip to content

feat: experimental Kotlin Multiplatform support (maps-compose-multiplatform) - #927

Open
kikoso wants to merge 15 commits into
mainfrom
feat/experimental-kmp-module
Open

kikoso wants to merge 15 commits into
mainfrom
feat/experimental-kmp-module

Conversation

@kikoso

@kikoso kikoso commented Jun 5, 2026 •

Copy link
Copy Markdown
Collaborator

Experimental Kotlin Multiplatform support: maps-compose-multiplatform shows a Google Map from shared Compose code on Android (through maps-compose) and iOS (through the Google Maps SDK for iOS), with an API that follows maps-compose.

GoogleMap(cameraPositionState = rememberCameraPositionState { position = cameraPosition(sydney, 12f) }) {
    Marker(state = rememberMarkerState(sydney), title = "Sydney")
    Circle(center = sydney, radius = 1_000.0)
    Clustering(items = places)
}

API

  • GoogleMap with CameraPositionState (two-way: moves from code, follows gestures, animate()), MapProperties, MapUiSettings, map clicks, long clicks and onMapLoaded.
  • Marker (draggable, tappable, tinted pin), Polyline, Polygon with holes, Circle. Each call keeps one native object that is updated in place, so nothing is cleared and recreated on recomposition.
  • Clustering reclusters as the camera zooms, once per zoom level, and zooms in on a cluster tap.
  • LatLng, CameraPosition and the clustering algorithms come from the multiplatform modules of android-maps-utils (feat: experimental Kotlin Multiplatform support (clustering, library, heatmaps) android-maps-utils#1774), currently 6.1.0-SNAPSHOT.
  • Not yet: custom marker icons, ground and tile overlays, Street View, MapEffect. The README lists them.

Demos

maps-compose-multiplatform-demo holds six demos (camera, markers, shapes, clustering, map settings, map clicks). The "Multiplatform demos" entry of maps-app and the iOS app show the same screens; the iOS app no longer has its own Swift list. -demo <index> (iOS) or --ei demo <index> (Android) opens one directly.

Build, publishing and CI

  • KmpPublishingConventionPlugin: explicit API, iOS arm64 and simulator arm64 targets, lint, Kover, Maven Central publishing as maps-compose-multiplatform.
  • Public API checks for the iOS klibs (Kotlin ABI validation) and the Android target (binary-compatibility-validator), committed under api/.
  • Publishing a release fails while mapsutilsKmp is a snapshot.
  • New Multiplatform (iOS) workflow on macOS: iOS simulator tests, API check, frameworks and the iOS app. The publish workflow moves to macOS, which the iOS klibs need.
  • Compose Multiplatform 1.7.3 to 1.12.1 (1.7.3 klibs no longer link with Kotlin 2.4). No iosX64: Compose Multiplatform dropped it.
  • The Xcode project is generated by create_project.rb and no longer checked in.

Tests

19 common tests (camera state, content registration and updates, clustering on zoom) run on the JVM and the iOS simulator. Locally: full CI build, the maps-app smoke and menu tests for the multiplatform entry on an API 36 emulator, and all six demos checked on both an Android emulator and an iOS simulator.

Before this can merge

android-maps-utils 6.1.0 has to ship with the KMP modules, and mapsutilsKmp move to it.

BEGIN_COMMIT_OVERRIDE
feat: experimental maps-compose-multiplatform library for Android and iOS
feat: shared camera state, map content and clustering in maps-compose-multiplatform
build: publish maps-compose-multiplatform with API checks, lint and iOS CI
END_COMMIT_OVERRIDE

@kikoso
kikoso force-pushed the feat/experimental-kmp-module branch from 1eff5db to 8852240 Compare June 5, 2026 15:42
@kikoso
kikoso marked this pull request as draft June 5, 2026 15:42
@googlemaps-bot

googlemaps-bot commented Jun 5, 2026 •

Copy link
Copy Markdown
Contributor

Code Coverage

Overall Project 44.37% -0.1% 🍏
Files changed 0% ❌

Module Coverage
debug 24.61% -0.2% ❌
Files
Module File Coverage
debug KmpMapActivity.kt 0% ❌
Demo.kt 0% -0.86% ❌

@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Coverage (unit tests)

Compared against cdf8b7f on main (#1044).

Module Line % Change Branch % Change
maps-compose 0.00% no change 0.00% no change
maps-compose-multiplatform 63.44% new 26.58% new
maps-compose-utils 2.17% no change 0.94% no change
maps-compose-widgets 0.00% no change 0.00% no change
TOTAL 9.13% 🔺 +8.68 3.23% 🔺 +3.06

Line and branch coverage from unit test reports. History is recorded on the coverage-history branch after each merge to main.

@kikoso kikoso changed the title feat: Add interactive KMP maps demos to iOS app & upgrade Google Maps SDK to 10.14.0 feat: experimental Kotlin Multiplatform support (maps-compose-multiplatform) Oct 2, 2026
@kikoso
kikoso marked this pull request as ready for review October 9, 2026 08:02
@kikoso
kikoso requested a review from a team as a code owner October 9, 2026 08:02
@googlemaps-bot

googlemaps-bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Coverage (instrumentation tests)

Overall Project 44.46% -0.1% 🍏
Files changed 0% ❌

Module Coverage
debug 24.62% -0.2% ❌
Files
Module File Coverage
debug KmpMapActivity.kt 0% ❌
Demo.kt 0% -0.86% ❌

@kikoso
kikoso force-pushed the feat/experimental-kmp-module branch from cda70c2 to 54c5bb8 Compare October 12, 2026 04:36
Comment thread gradle/libs.versions.toml Dismissed
@kikoso
kikoso force-pushed the feat/experimental-kmp-module branch from 51bde83 to 5fe397b Compare October 14, 2026 16:58
kikoso and others added 14 commits October 15, 2026 20:00
…anch

Adds common-code clustering to maps-compose-multiplatform via the
experimental KMP modules of android-maps-utils (maps-model, clustering):
clusterMarkers() runs NonHierarchicalDistanceBasedAlgorithm in
commonMain and ClusteredGoogleMap renders the resulting clusters, so
Android and iOS produce identical clusters from shared code.

Consumption paths (see settings.gradle.kts): publishToMavenLocal from
../android-maps-utils plus -PuseMavenLocal=true (full build works, this
is the default), or -PuseLocalMapsUtils=true for a composite build
(platform compilations work; shared-metadata compilation is skipped by
Kotlin's granular-metadata transform across included builds and fails).

Note: linkPodDebugFrameworkIosArm64 fails on this branch with or without
this change (Kotlin/Native cache failure on compose-ui 1.7.3
uikitarm64); simulator link and all target compilations pass.

Claude-Session: https://claude.ai/code/session_01225X6MnAqkyCF7Xones6WY
The maps-compose-multiplatform module now depends on
com.google.maps.android:maps-model and :clustering from the
feat/experimental-kmp-clustering branch of android-maps-utils, which are
not published to any remote repository. Check out that branch and
publish the two modules to the runner's mavenLocal in the lint, test and
instrumentation workflows, and set USE_MAVEN_LOCAL so the compose build
resolves them from there.

Claude-Session: https://claude.ai/code/session_01225X6MnAqkyCF7Xones6WY
com.google.maps.android:clustering duplicated the classes of the
android-maps-utils-clustering AAR that maps-compose-utils pulls from
Maven Central, failing maps-app's checkDebugDuplicateClasses. Depend on
android-maps-utils-clustering / android-maps-utils-maps-model instead
(matching the renamed KMP publications) so Gradle resolves both paths to
one module; mavenLocal shadows the Central AAR with the API-compatible
KMP artifact.

Claude-Session: https://claude.ai/code/session_01225X6MnAqkyCF7Xones6WY
…OS CI

- KmpPublishingConventionPlugin: explicit API mode, iosArm64 and
  iosSimulatorArm64, lint, Kover and Maven Central publishing as
  maps-compose-multiplatform
- Public API checks for the iOS klibs (Kotlin ABI validation) and the
  Android target (binary-compatibility-validator), in api/
- Publishing a release fails while it depends on a maps-utils snapshot
- New macOS workflow builds the iOS targets and the iOS demo app
- The publish workflow runs on macOS, which the iOS klibs need
…ment the KMP build

- commonTest for clusterMarkers, run as Android host tests and on the
  iOS simulator
- iosApp/README.md replaces BUILD_KMP.md; the Xcode project is generated
  by create_project.rb and no longer checked in
- AGENTS.md describes the multiplatform module, its API checks and the
  snapshot dependency
…-multiplatform

Replaces the prototype API with one that follows maps-compose:

- GoogleMap(cameraPositionState, properties, uiSettings, onMapClick,
  onMapLongClick, onMapLoaded) { content }
- CameraPositionState follows the map both ways and can animate
- Marker with MarkerState (draggable, tappable, tinted pin), Polyline,
  Polygon with holes and Circle; each keeps one native object per call
  instead of clearing the map on every update
- Clustering reclusters as the camera zooms and zooms in on cluster taps
- Line widths are density-independent on both platforms

Demos move to maps-compose-multiplatform-demo, shared by maps-app and the
iOS app, which now hosts them instead of a Swift list. Tests cover the
camera state, content registration and clustering on the JVM and iOS.
The iOS CameraPosition in android-maps-utils now has value equality
(googlemaps/android-maps-utils#1774), so the saver test can assert the
whole position again.
…form

Kotlin 2.4.20's abiValidation covers the Android target of a multiplatform
library and expects its dump in api/android/. Drop the
binary-compatibility-validator workaround that dumped it to api/ and move
the existing dump, which is unchanged.
* feat: introduce experimental KMP maps module wrapping Google Maps on Android and MapKit on iOS

* feat: migrate iOS multiplatform map implementation to native Google Maps iOS SDK via CocoaPods

* feat: add interactive maps demos to iOS app & upgrade Google Maps SDK to 10.14.0

* fix(ios): declare DeveloperSecrets.swift output path & add BUILD_KMP.md

* feat: consume multiplatform clustering from android-maps-utils KMP branch

Adds common-code clustering to maps-compose-multiplatform via the
experimental KMP modules of android-maps-utils (maps-model, clustering):
clusterMarkers() runs NonHierarchicalDistanceBasedAlgorithm in
commonMain and ClusteredGoogleMap renders the resulting clusters, so
Android and iOS produce identical clusters from shared code.

Consumption paths (see settings.gradle.kts): publishToMavenLocal from
../android-maps-utils plus -PuseMavenLocal=true (full build works, this
is the default), or -PuseLocalMapsUtils=true for a composite build
(platform compilations work; shared-metadata compilation is skipped by
Kotlin's granular-metadata transform across included builds and fails).

Note: linkPodDebugFrameworkIosArm64 fails on this branch with or without
this change (Kotlin/Native cache failure on compose-ui 1.7.3
uikitarm64); simulator link and all target compilations pass.

Claude-Session: https://claude.ai/code/session_01225X6MnAqkyCF7Xones6WY

* ci: publish KMP maps-utils modules to mavenLocal before building

The maps-compose-multiplatform module now depends on
com.google.maps.android:maps-model and :clustering from the
feat/experimental-kmp-clustering branch of android-maps-utils, which are
not published to any remote repository. Check out that branch and
publish the two modules to the runner's mavenLocal in the lint, test and
instrumentation workflows, and set USE_MAVEN_LOCAL so the compose build
resolves them from there.

Claude-Session: https://claude.ai/code/session_01225X6MnAqkyCF7Xones6WY

* fix: consume KMP maps-utils under its public artifactIds

com.google.maps.android:clustering duplicated the classes of the
android-maps-utils-clustering AAR that maps-compose-utils pulls from
Maven Central, failing maps-app's checkDebugDuplicateClasses. Depend on
android-maps-utils-clustering / android-maps-utils-maps-model instead
(matching the renamed KMP publications) so Gradle resolves both paths to
one module; mavenLocal shadows the Central AAR with the API-compatible
KMP artifact.

Claude-Session: https://claude.ai/code/session_01225X6MnAqkyCF7Xones6WY

* build: consume the maps-utils 6.1.0-SNAPSHOT instead of a mavenLocal build

* build: publish maps-compose-multiplatform with API checks, lint and iOS CI

- KmpPublishingConventionPlugin: explicit API mode, iosArm64 and
  iosSimulatorArm64, lint, Kover and Maven Central publishing as
  maps-compose-multiplatform
- Public API checks for the iOS klibs (Kotlin ABI validation) and the
  Android target (binary-compatibility-validator), in api/
- Publishing a release fails while it depends on a maps-utils snapshot
- New macOS workflow builds the iOS targets and the iOS demo app
- The publish workflow runs on macOS, which the iOS klibs need

* test: run the multiplatform clustering tests on the JVM and iOS, document the KMP build

- commonTest for clusterMarkers, run as Android host tests and on the
  iOS simulator
- iosApp/README.md replaces BUILD_KMP.md; the Xcode project is generated
  by create_project.rb and no longer checked in
- AGENTS.md describes the multiplatform module, its API checks and the
  snapshot dependency

* feat: shared camera state, map content and clustering in maps-compose-multiplatform

Replaces the prototype API with one that follows maps-compose:

- GoogleMap(cameraPositionState, properties, uiSettings, onMapClick,
  onMapLongClick, onMapLoaded) { content }
- CameraPositionState follows the map both ways and can animate
- Marker with MarkerState (draggable, tappable, tinted pin), Polyline,
  Polygon with holes and Circle; each keeps one native object per call
  instead of clearing the map on every update
- Clustering reclusters as the camera zooms and zooms in on cluster taps
- Line widths are density-independent on both platforms

Demos move to maps-compose-multiplatform-demo, shared by maps-app and the
iOS app, which now hosts them instead of a Swift list. Tests cover the
camera state, content registration and clustering on the JVM and iOS.

* feat(kmp-demo): add shared multiplatform Location Flow demo

* docs(kmp-demo): add TODO referencing android-maps-utils#1818 in PlatformLocationSource.android.kt

* chore(kmp-demo): address review feedback on permission handling, manifest, and trail cap

---------

Co-authored-by: Enrique López Mañas <eenriquelopez@gmail.com>
@kikoso
kikoso force-pushed the feat/experimental-kmp-module branch from 5fe397b to 373bc4e Compare October 15, 2026 18:00
Comment thread gradle/libs.versions.toml
mapsutils = "6.0.0"
# Multiplatform modules from the android-maps-utils KMP branch, published as snapshots.
mapsutilsKmp = "6.1.0-SNAPSHOT"
composeMultiplatform = "1.12.1"
Comment thread gradle/libs.versions.toml
mapsutils = "6.0.0"
# Multiplatform modules from the android-maps-utils KMP branch, published as snapshots.
mapsutilsKmp = "6.1.0-SNAPSHOT"
composeMultiplatform = "1.12.1"
Comment thread gradle/libs.versions.toml
mapsutils = "6.0.0"
# Multiplatform modules from the android-maps-utils KMP branch, published as snapshots.
mapsutilsKmp = "6.1.0-SNAPSHOT"
composeMultiplatform = "1.12.1"

This branch has not been deployed

No deployments
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.

4 participants