moko-maps icon indicating copy to clipboard operation
moko-maps copied to clipboard

Will this library work with KMP and Compose for iOS?

Open realityexpander opened this issue 1 year ago • 7 comments

realityexpander avatar Aug 18 '23 20:08 realityexpander

Doesn't seem like

sdzshn3 avatar Sep 25 '23 05:09 sdzshn3

What is the suggested alternative?

realityexpander avatar Sep 25 '23 06:09 realityexpander

I have done something like this

@Composable
expect fun GoogleMaps(
    modifier: Modifier,
    markers: List<MapMarker>? = null,
    cameraPosition: CameraPosition? = null,
    cameraPositionLatLongBounds: CameraPositionLatLongBounds? = null,
    polyLine: List<LatLong>? = null
)
@Composable
actual fun GoogleMaps(
    modifier: Modifier,
    markers: List<MapMarker>?,
    cameraPosition: CameraPosition?,
    cameraPositionLatLongBounds: CameraPositionLatLongBounds?,
    polyLine: List<LatLong>?
) {

    val cameraPositionState = rememberCameraPositionState()

    LaunchedEffect(cameraPosition) {
        cameraPosition?.let {
            cameraPositionState.animate(
                CameraUpdateFactory.newLatLngZoom(
                    LatLng(
                        it.latLong.latitude,
                        it.latLong.longitude
                    ), it.zoom
                )
            )
        }
    }

    LaunchedEffect(cameraPositionLatLongBounds) {
        cameraPositionLatLongBounds?.let {

            val latLngBounds = LatLngBounds.builder().apply {
                it.coordinates.forEach { latLong ->
                    include(LatLng(latLong.latitude, latLong.longitude))
                }
            }.build()

            cameraPositionState.move(
                CameraUpdateFactory.newLatLngBounds(latLngBounds, it.padding)
            )
        }
    }

    GoogleMap(
        cameraPositionState = cameraPositionState,
        modifier = modifier
    ) {
        markers?.forEach { marker ->
            Marker(
                state = rememberMarkerState(
                    key = marker.key,
                    position = LatLng(marker.position.latitude, marker.position.longitude)
                ),
                alpha = marker.alpha,
                title = marker.title
            )
        }

        polyLine?.let { polyLine ->
            Polyline(
                points = List(polyLine.size) {
                    val latLong = polyLine[it]
                    LatLng(latLong.latitude, latLong.longitude)
                },
                color = Color(0XFF1572D5),
                width = 16f
            )
            Polyline(
                points = List(polyLine.size) {
                    val latLong = polyLine[it]
                    LatLng(latLong.latitude, latLong.longitude)
                },
                color = Color(0XFF00AFFE),
                width = 8f
            )
        }

    }
}
@Composable
actual fun GoogleMaps(
    modifier: Modifier,
    markers: List<MapMarker>?,
    cameraPosition: CameraPosition?,
    cameraPositionLatLongBounds: CameraPositionLatLongBounds?,
    polyLine: List<LatLong>?
) {
    val mapsView = remember {
        GMSMapView()
    }

    UIKitView(
        modifier = modifier.fillMaxSize(),
        interactive = true,
        factory = {
            mapsView
        },
        update = { view ->
            cameraPosition?.let {
                view.setCamera(
                    GMSCameraPosition.cameraWithLatitude(
                        it.latLong.latitude,
                        it.latLong.longitude,
                        it.zoom
                    )
                )
            }

            cameraPositionLatLongBounds?.let {

                val bounds = GMSCoordinateBounds()
                it.coordinates.forEach {
                    bounds.includingCoordinate(
                        CLLocationCoordinate2DMake(
                            latitude = it.latitude,
                            longitude = it.longitude
                        )
                    )
                }
                GMSCameraUpdate().apply {
                    fitBounds(bounds, it.padding.toDouble())
                    view.animateWithCameraUpdate(this)
                }
            }

            markers?.forEach { marker ->
                GMSMarker().apply {
                    position = CLLocationCoordinate2DMake(
                        marker.position.latitude,
                        marker.position.longitude
                    )
                    title = marker.title
                    map = view
                }
            }

            polyLine?.let { polyLine ->
                val points = polyLine.map {
                    CLLocationCoordinate2DMake(it.latitude, it.longitude)
                }
                val path = GMSMutablePath().apply {
                    points.forEach { point ->
                        addCoordinate(point)
                    }
                }

                GMSPolyline().apply {
                    this.path = path
                    this.map = view
                }
            }
        }
    )
}

sdzshn3 avatar Sep 25 '23 07:09 sdzshn3

Thanks for the sample code! I can see that the code is using the native libraries on ios and android.

I'm primarily and Android native dev, so iOS is still a bit mysterious for me, especially without having example code to work from.

Is there any other special handling to use this code? Like the cocopods setup in this project? Or just a standard google setup?

Is there a more complete example of your code that I could reference for this?

Im confused about what needs to be in place on the iOS side to make this work. I can handle the Android side.

Thanks in advance!

realityexpander avatar Sep 26 '23 03:09 realityexpander

I'm also in a stage of trail and error to make the maps work on both platforms.

As I keep adding more features, I started to have a feel like, it's better to use GoogleMaps View directly and set the view as AndroidView in Compose. This way we have a GoogleMap object which gives us full control and write better code.

And regarding integration of Maps in ios, I have used cocoapods.

in shared gradle:

kotlin {
    cocoapods {
        // ...
        pod("GoogleMaps") {
            version = "8.2.0"
        }
    }
}

After that once you do a gradle sync, you should be able to use GoogleMaps related classes in iosMain of shared module.

For API usage, refer official docs https://developers.google.com/maps/documentation/ios-sdk/config

sdzshn3 avatar Sep 26 '23 06:09 sdzshn3

I have finally got the Android and iOS displaying maps with interactivity. There are some features on iOS that are not working properly, but the basic functionality is implemented.

Check out my solution here:

https://github.com/realityexpander/ContactsComposeMultiplatform

realityexpander avatar Sep 29 '23 22:09 realityexpander

I'm new in KMP and Compose, can you guys give me a beginner instruction on how to integrate Google Maps in iOS?

andiosdev avatar Jul 22 '24 03:07 andiosdev