mapbox / mapbox-maps-android

Interactive, thoroughly customizable maps in native Android powered by vector tiles and OpenGL.
https://www.mapbox.com/mobile-maps-sdk
Other
442 stars 128 forks source link

Add Compose Multiplatform implementation #2281

Open rschattauer opened 4 months ago

rschattauer commented 4 months ago

New Feature

There is Compose Multiplatform https://www.jetbrains.com/lp/compose-multiplatform/ out, you already started doing the compose extension for Android, would it be possible to get a dependency that can be used within Kotlin Multiplatform compose?

Why

To not implement iOS and Android (and maybe another target) separately.

rkreienbuehl commented 4 months ago

This would be great

brendanw commented 3 months ago

Huge +1 from a mapbox customer who is all in on compose multiplatform

sigmadeltasoftware commented 1 month ago

+1 from another avid user.

Personally, I would like to suggest to maybe consider the Android Search SDK (https://docs.mapbox.com/android/search/guides/) as a suitable PoC as most of the components used in the SDK have a readily available KMP alternative.

ColtonIdle commented 3 weeks ago

this would likely cause my team to move to mapbox. does not seem like google maps will be multiplatform anytime soon.

sigmadeltasoftware commented 3 weeks ago

this would likely cause my team to move to mapbox. does not seem like google maps will be multiplatform anytime soon.

Honestly, I've been integrating the MapBox iOS SDK into my Compose Multiplatform project for a few days now and got it into a semi-decent working state, but the journey has been such an absolute pain that I don't believe it's happening anytime soon.

The iOS SDK is very fragile (inter-incompatibility between frameworks for example because some already integrate the other) and the API itself is sometimes completely different from what the other SDK's do (f.e. all other SDK's use driving \ driving-traffic for the profile identifier in the Directions SDK, iOS uses automobile and automobileAvoidingTraffic 😅 : https://docs.mapbox.com/ios/directions/api/2.11.1/Structs/ProfileIdentifier.html)

luca992 commented 3 weeks ago

@sigmadeltasoftware do you have a sample or some code snippets of how you linked the MapBox iOS SDK to your project and rendered it in a composable? I was attempting to do that not long ago but I couldn't get it working.

rschattauer commented 3 weeks ago

@luca992 I have an example here: https://github.com/rschattauer/compose_multiplatform This is my current solution that I will also talk about at DroidCon Berlin in a month. Feedback is greatly appreciated!

luca992 commented 3 weeks ago

@rschattauer thanks appreciate it. Saving me a bunch of time 🙏

sigmadeltasoftware commented 3 weeks ago

@sigmadeltasoftware do you have a sample or some code snippets of how you linked the MapBox iOS SDK to your project and rendered it in a composable? I was attempting to do that not long ago but I couldn't get it working.

My implementation is very similar to @rschattauer, the only difference being that I make use of the UIViewController instead as I'm using SwiftUI for the MapBox integration in iOS:

actual fun MapBoxView(
    state: MapBoxViewContract.State,
    modifier: Modifier,
    postInput: (MapBoxViewContract.Inputs) -> Unit
) {
  ... 
  val stateFlow = remember { MutableStateFlow(state) }
  val mapBoxViewControllerHandler: MapBoxViewControllerHandler = koinInject()
  val postInputDelegate = remember { object : MapBoxViewPostInputDelegate { ... } }

  val factory = remember { mapBoxViewControllerHandler.loadMapBoxViewController(postInputDelegate, state, stateFlow) as UIViewController }

    LaunchedEffect(state) {
        Napier.ed { "New state received, emitting to iOS" }
        stateFlow.emit(state)
    }

    Box(modifier.windowInsetsPadding(WindowInsets.systemBars)) {
        UIKitViewController(
            factory = { factory },
            modifier = Modifier.fillMaxSize().defaultMinSize(300.dp).border(2.dp, Color.Blue),
        )
    }
}

The current setup I liked most for now, is using a callbackhandler (MapBoxViewControllerHandler) provided by Koin to both iOS and the common module, and then use a MutableStateFlow (that gets transformed into a SkieSwiftFlow by Touchlabs' SKIE) as a reactive component that emits my MVI state changes to iOS.