Closed louwers closed 9 hours ago
For the record, we were able to get MapLibre working in our KMP app (both Android and iOS). It was however a home-grown solution, and there were some rough edges.
@tarkvara Can you share more details?
I wasn't ambitious enough to create a KMP library, so Android and iOS directly refer to the native libraries. Perhaps somebody with a better understanding of the KMP build tools can wrap them together into a single KMP library.
For Android, it was enough to add maplibre-android = { group = "org.maplibre.gl", name = "android-sdk", version = "11.0.1" }
and the corresponding dependency under androidMain.dependencies.
For iOS, I added
with (iosTarget.compilations) {
getByName("main") {
cinterops {
create("MapLibre") {
packageName("org.maplibre")
compilerOpts(
"-framework",
"MapboxLibre",
"-Fsrc/iosFrameworks/MapLibre.xcframework/$subDir"
)
}
}
}
}
iosTarget.binaries.all {
// Tell the linker where the framework is located.
linkerOpts(
"-framework",
"MapLibre",
"-F../composeApp/src/iosFrameworks/MapLibre.xcframework/$subDir"
)
}
Which unfortunately isn't quite correct; the Gradle build doesn't correctly link, so I had to build the app from within Xcode.
As I said, it seems to work for our app, but I wouldn't recommend it as a general solution.
Hi! I just posted this today this in Slack and then found this issue.
Hello! I'm just wondering if there is anybody already working on maplibre in compose multiplatform. I think it is the missing piece in compose multiplatform app development - maps. I have already started creating a compose multiplatform library that uses maplibre native(ios and android) under the hood. I reworked the expressions to kotlin and the first tests look promising: loading styles, updating camera, adding layers and sources programatically. But maybe before going any further I just wanted to check if there is already a project doing this exact same thing. Is there? Thanks :slightly_smiling_face:
I was thinking of creating a proper opensource library for it, but I wanted to make sure it didn't exist yet. But seeing this issue, gives me enough motivation to continue.
Thank you for posting this ticket, @louwers !
@amirhammad Wow, that's cool! There exists in fact a Compose library using MapLibre, Ramani-Maps. But it is for Jetpack Compose and Android-only. Additionally, I am not sure if the API of this library has been designed to support the whole feature set of MapLibre in mind. (see https://github.com/ramani-maps/ramani-maps/issues/77 which I just opened) At the very least, it can serve as a base or inspiration how the API could look like and how to wire together MapLibre with Compose in general. (But I just realized that I didn't read your cited message to the end - you already did that)
I am also highly interested in this, though I just started using Compose a few months ago, so I don't feel confident to help implementing a Compose library and design its API just yet. In terms of designing a perfect compose API, it might also be worth looking at and learning from the Google's Maps Compose library.
Hej! Co-author of Ramani-Maps here. We would love it if Ramani-Maps worked with Compose Multiplatform! Back when we started, I quickly tried to get Maplibre to run on Compose Multiplatform on my Linux system ("natively", i.e. not with a WebView and Javascript) and my conclusion was that it would take some work there.
If you manage to make Ramani-Maps work "natively" on iOS or Desktop, I would be willing to have a look and help bring that upstream. I am however not very open to solving it with a WebView and Javascript :see_no_evil:.
Additionally, I am not sure if the API of this library has been designed to support the whole feature set of MapLibre in mind.
Completely open to contributions! And of course if you feel like you will be better off on your own fork, feel free (it's MPLv2-licensed).
Looping in @Archdoog here. We currently have a fork of Ramani that's a bit more active (would love to upstream but it's been a bit tough getting responses, and Ramani is currently a good bit broader with Mapbox support, drawing, and a lot of things besides just a core composable library).
We are not presently targeting compose multi platform but aren't opposed to it :)
Does anyone on the thread know how different or related Jetpack Compose and Compose Multiplatform are? EDIT: It looks like the JetBrains README has a helpful excerpt. The devil lies in the details, but this looks promising:
Compose Multiplatform shares most of its API with Jetpack Compose, the Android UI framework developed by Google. You can use the same APIs to build user interfaces for both Android and iOS.
Assuming they are similar, I think it would be a shame to have too many diverging approaches, since we are all going to run into most of the same challenges. Jacob and I have put a lot of work into getting camera stuff correct, as this is a HUGE pain in every similar UI framework (same on iOS, where we are developing a similar wrapper for SwiftUI).
would love to upstream but it's been a bit tough getting responses
@ianthetechie: have I missed questions somewhere? :confused:
Also note that we have dropped Mapbox support (because Mapbox doesn't play nice with us).
Hey @JonasVautherin! I think @ianthetechie had some initial chats with you on the maplibre slack channel. We tried reaching out there a handful of times.
As for a path forward, I'd suggest we set up a call to give you an introduction to where we've gone from forking ramani to where https://github.com/Rallista/maplibre-compose-playground sits now. There are a few key differences that we could chat about.
You are always welcome to put this on the agenda for the MapLibre Native TSC Meeting as well.
We tried reaching out there a handful of times.
I see. I have not been active on Slack there for a while indeed. The best way to upstream changes is probably to open an issue/PR on the git repository (i.e. the MapLibre Slack is not the official way to reach Ramani-Maps).
We can definitely have a call, I would be happy to hear your thoughts. However I probably won't bring your fork upstream myself. I am happy to discuss, review and merge contributions (on a best-effort basis), but someone would have to make those contributions :blush:. If that isn't possible, then as I said you are welcome to keep working on your fork (as long as you honour the licence) :+1:.
This said, I wouldn't say Ramani is not active. I believe I have been pretty responsive regarding issues and PRs on the repo. To be honest, I find it a bit unfair to say it has been "tough getting responses".
~Does anyone on the thread know how different or related Jetpack Compose and Compose Multiplatform are?~
Compose Multiplatform is a soft fork of Jetpack Compose, for example, the package names are the same. So theoretically, one could switch out the dependency and be ready for multiplatform. Furthermore, some Jetpack compose APIs may not be available on multiplatform, i.e. they cannot be used or need to have an implementation for every platform. For example stringResource(stringResId: Long)
, painterResource(drawableResId: Long)
etc. are only available on the Android platform (as they access Android resources).
Otherwise, so that the library itself is multiplatform and not only uses a multiplatform library as a dependency, it itself needs to be set up like one, i.e. with the directly structure like src/commonMain
, src/androidMain
etc. and the correct gradle configuration.
I recently migrated a smallish Java library to a Kotlin Multiplatform library (nothing with Compose though). Maybe this can help:
Jacob and I have put a lot of work into getting camera stuff correct, as this is a HUGE pain in every similar UI framework (same on iOS, where we are developing a similar wrapper for SwiftUI).
Interesting, I would think that the easiest approach would be to ... uh ... basically don't worry about camera animations at all but leave that up to Compose. I.e. just expose the camera position on the API and users would just use the usual Compose stuff for animations. Or is even that a PITA? (I am somewhat of a newbie with Compose, so I only have a very rough idea how that would look like.)
Anyway, there is talk about a call - I'd like to join too. Did someone mention a date or a doodle for date-finding? If not, @ianthetechie would you mind setting this up? You two seem to be the ones that advanced the most from what I read here.
+1 on the call initiative!
Hi! Seb from JetBrains / Compose Multiplatform here. Would be awesome to have MapLibre available for Compose Multiplatform apps on iOS and Android (or even beyond!) – Let us know if there is something we can help with or if there's any questions that come up during your discussions – happy to connect!
I've created a Doodle here so we can all get on a call for an hour to discuss :) https://doodle.com/meeting/participate/id/b44RqJ7b
See you soon!
Thanks for organising this. I'd be interested in joining too, if we can find a good slot 😺
By the way, there is another. When one searches for MapLibre Compose on DuckDuckGo, one will find this: https://github.com/dellisd/maplibre-compose
It's a bit older, but just yesterday, the guy added new commits.
So, to summarize, there are now:
Ramani-Maps Android-only, published on Maven-Central, exposes only small subset of the underlying map functionality, development mostly stopped, by @JonasVautherin, @RomanBapst
maplibre-compose incomplete, development probably stopped, not published on Maven, Android only, by @dellisd
MapLibre Compose Playground based off Ramani-Maps but with API more similar to MapLibreSwiftUI, Android-only, published on Maven-Central, unknown how complete it is, in very active development, by @ianthetechie @Archdoog
ComposeMap, for Android and iOS, source code not published, hence status and completion unknown, by @amirhammad
Thanks for the mention!
I don't have any concrete plans to continue working on maplibre-compose at the moment, but I may revisit it again in the future depending on the needs of my side projects.
Some other prior art I can throw into this thread which may be of some use:
There is also a library in progress by @skamirmaps, which he described on his blog https://amir.sk/32/compose-map-intro/
Yes, that's the "ComposeMap" I mentioned above. But as long as the source is not available, TBH it's not really interesting because one cannot really talk about it on a technical level.
@westnordost, @michalgwo : Hello there! Sorry for replying a bit late. I'm still working on deploying the library to a maven repository.
If anybody would like to try it out, I invite you just to just fill out the form and I will provide you with the library to play around with when it's ready(should be this weekend 🤞) You can find more info skamirmaps samples repository. There you can already see, although not be able to compile yet, how it can be used.
For now, I decided to not disclose the source code to general public, however I might reconsider later.
If anybody is interested to know more about technical details or discuss possible collaboration, please contact me at maps@amir.sk.
Thank you!
Hey @amirhammad thanks for giving an update on your progress! Proprietary software is out of scope of the MapLibre project and advertising/discussing proprietary software should happen on other channels. Of course if you run into any challenges while integrating MapLibre Native that would be in scope in a separate issue, we support all users/integrators of MapLibre Native here.
This discussion is intended to bring people together to discuss and develop an open source Compose Multiplatform library for MapLibre. Thanks for understanding.
I'm working on a Kotlin Multiplatform app using MapLibre, and have a prototype of a Multiplatform wrapper for MapLibre Native. Currently my prototype supports:
Currently the code is under a package in my app (https://github.com/sargunv/train-tracker-app), but as it develops and I nail down patterns for a representative subset of features, I intend to split it off into its own library. Feel free to check out the code here: https://github.com/sargunv/train-tracker-app/tree/main/maplibre-compose
Some immediate TODOs I have are:
Once some API patterns are nailed down for those TODOs, it's mostly a matter of following those patterns to add support for all the various layer/source configuration (which I'd probably rely on PRs for, beyond my own use cases)
Nice work @sargunv!
Out of curiosity: do I understand correctly that this is a wrapper around MapLibre-iOS (what I see here) and MapLibre-Android (see here)?
I guess I am a little confused because you mention that it is a "Multiplatform wrapper for MapLibre Native". But it feels like it is wrapping the Android/iOS SDKs, not the MapLibre Native (the C++ library), right? Or am I missing something?
Ah yup, it's a multiplatform wrapper around the android/iOS sdks (which I thought are part of the MapLibre Native project but I might have my terminology mixed up)
Not fundamentally opposed to interfacing with the actual native library itself; I just chose the route that felt easier to get off the ground
They are both part of the MapLibre Native project! So "Multiplatform wrapper for MapLibre Native" is correct.
Not fundamentally opposed to interfacing with the actual native library itself; I just chose the route that felt easier to get off the ground.
Definitely true. Especially since we don't have a C FFI yet (which seems the way to go if you want to interface with native libraries directly with Kotlin Multiplatform). I think this will be developed over the course of the next year, since it is needed for getting the most performant implementation for Flutter possible, something Toyota has indicated interest in.
But for now building on the Android and iOS SDKs seems to be the way to go for sure. They are widely in use and are not going anywhere.
They are both part of the MapLibre Native project! So "Multiplatform wrapper for MapLibre Native" is correct.
Right, my mistake. "Native" is a bit of a strange word: on Android, the "Native Development Kit" (C/C++) is in opposition to the "Software Development Kit" (Java/Kotlin). But then some people use "native" to mean it's using what you find in the official Android documentation (e.g. not a Javascript wrapper). It seems like "MapLibre-Native" is just the name of the project, which again is different.
Especially since we don't have a C FFI
Android can definitely interface with C++ over JNI, and I think iOS can as well through Objective-C++ :thinking:. C is probably better for interoperability in general: for instance I am not sure if Go can easily call C++. I am not sure I understand the performance issue with Flutter, though.
From where I stand, what prevents me from using the C++ library with KMP is not the API, but missing implementation. For instance the annotations are implemented in the Android module, not in C++ (if I understand correctly). Or am I missing something?
Android can definitely interface with C++ over JNI, and I think iOS can as well through Objective-C++ 🤔.
This is exactly what we are using for the Android and iOS SDKs. However, you could in theory use Kotlin Multiplatform's Interoperability with C as well. As you mention, you would need to re-implement some of the platform-dependent implementations (e.g. for making HTTP requests). Also the SDKs themselves contain additional functionality, although annotations do exist as a concept in the C++ Core as well.
you would need to re-implement some of the platform-dependent implementations (e.g. for making HTTP requests)
But I guess also the rendering engine, right? That felt like the complicated part to me :innocent:. But maybe that alone justifies having official wrappers for Android/iOS the way they are now, and going for a KMP approach like @sargunv is doing :+1:.
FYI the current one and only HTTP library for KMP that works for both Android and iOS is Ktor Client. OkHttp is multiplatform, too, but AFAIK only for JVM and JS. And for parsing JSON (and thus GeoJson), the go-to solution is Kotlinx.serialization-json, which is also multiplatform for any target.
But I guess also the rendering engine, right?
@JonasVautherin No, the rendering engine is part of the C++ Core.
And for parsing JSON (and thus GeoJson), the go-to solution is Kotlinx.serialization-json, which is also multiplatform for any target.
@westnordost JSON parsing is is all implemented in C++. You wouldn't need to touch it.
FYI the current one and only HTTP library for KMP that works for both Android and iOS is Ktor Client.
You would need some kind of C++ implementation, because the C++ code makes the requests. For example platform/default
has a HttpFileSource implementation that uses curl, iOS uses APIs part of Foundation, Android delegates the call to Kotlin land, etc.
Anyway, I don't want to derail the discussion. Just wanted to mention it as a possibility.
After a lot of consideration (maybe too much!) I realised skamirmaps should be open-source. https://github.com/skamirmaps/skamirmaps All outside contributions are welcome. Let's come up with APIs that are easy to use!
Thank you
I just want to share that all the TODOs I mentioned in my previous comment are now implemented (except for the one about writing tests).
My experimental Multiplatform wrapper for the Maplibre SDKs now supports:
The code is available in the repo linked in my previous comment above.
Some more immediate TODOs before I feel ready to publish a v0.1 and open up to PRs:
Things I'd like to explore soon after v0.1:
https://github.com/sargunv/maplibre-compose
I’ve just published the first release to Maven! Docs are light at the moment but there’s source code for a demo app showcasing common use cases. Feedback and PRs welcome!
StreetComplete is looking to implement an iOS version of the app. The largest blocker is that there is no Compose Multiplatform library that uses MapLibre Native. If you are also interested in this, please reach out to @westnordost, maybe some kind of collaboration to work on this is possible.
Jetbrains has a template available here: https://github.com/KevinnZou/compose-multiplatform-library-template/tree/main
An example Compose Multiplatform library is WebView for JetBrains Compose Multiplatform
It uses Native C Interop: https://kotlinlang.org/docs/native-c-interop.html#simple-example with
cinterop
.Related PR: https://github.com/maplibre/maplibre-native/pull/1254