Closed westnordost closed 8 months ago
Is it worth pinning this issue?
Also there's new approaches to this, like Beeware, which could be an interesting alternative somewhere in the future, since it also offers native desktop apps as well as browser apps (for example for chrome books).
It would also require a full rewrite into python, but all API calls are native Python and they are translated while compiling or while running on the python virtual machine to native API calls. So there's zero code which needs to be platform-native.
The advantage of using Python is clearly the amount of libraries available, for communication with OSM, OSM data etc.
Just my two cents :)
Well, rewriting the entire app is obviously out of question and out of scope. There are many other cross platform frameworks available.
@westnordost yeah I know. Beeware is also in a very very alpha stage, but quite an interesting concept. :)
I'm a python developer and would have fun to invest some time into such a project. But at the current stage of Beeware this doesn't make any sense. :)
Thanks for creating a dedicated issue for this!
I've created a branch, set up a "Shared" module and integrated it into an empty Xcode project. The build succeeds and I can use the code inside the Swift files. (For testing, I've moved StringMapChange
into the "Shared" module.)
It looks as if using the Kotlin code on both platforms could work. When looking at the bigger picture, however, I can't help but agree with you when you point out that it will be "enormous effort". The main issue at the moment that I see is that a lot of the classes' dependencies are Android-specific, or written in Java.
As an example, take the dependency on osmapi. A lot of the StreetComplete code is importing that library, because it contains basic classes such as BoundingBox
and LatLon
. In order for iOS to be able to use it, one would probably need to port that library so that it is usable with Kotlin Native, too.
Yes, correct. This is why I think the Multi-OS Engine approach may be more feasible.
As for that kind of dependencies, it would be possible of course to wrap the classes from osmapi. Unfortunately, Kotlin, unlike Swift doesn't have a feature that would allow to make third-party classes implement interfaces via extension functions, however, there is an experimental feature to have inline
classes. That, or typealiases could maybe be used to have such a very thin wrapper layer.
Hi thanks for the clarification! I was already seeking for an alternative option to be able to contribute to OSM on my iOS - I was quite happy with my legacy Android phone to gain points and correct small glitches. Unfortunately I'm not an iOS developer but very probably the efforts are enormous. But anyway I can also say there is demand :-)
Anyway THANKS for the efforts in the Android edition, I really like the app!
@wtimme and I analyzed in a little more detail what needs to be done.
Anything view- and Android-related needs to be done from scratch. In a little more detail with very rough (week-wise) estimations:
So in total about 5 months or more. Some things (~2 months) are not so important for the core functionality and can be added later or bit by bit.
These are things that are pure Kotlin but currently have Android and no Java dependencies. Most classes that are in the /data/ directory. All DAOs to access the database, almost all controllers (classes that manage DAOs), download and upload logic, metadata, data, diff data, filters parser (similar to Overpass Wizard syntax) and all the quest types.
QuestAutoSyncer
depends on Android location framework and must be wrapped (at least), other location-related stuff (1W)SharedPreferences
must be wrapped behind an interface so that UserDefaults
can be used instead for iOS (maybe https://github.com/russhwolf/multiplatform-settings could be used) (1W)ApplicationConstants
should be injected instead (1W)CopyOnWriteArrayList
to manage listeners, must replace with something else that is not Java (0.5W)Abbreviations
and CountryInfos
are in Java (because they are candidates to become libraries) and must be replaced in iOS with an own implementation (2W)So, about 6 months or less (~1-3 months less) if one just ports/copypastas the used java libraries into swift code or finds very similar ready-made libraries that do the same.
As far as a minimum viable product is concerned:
CopyOnWriteArrayList
, the usage of Date
in the filters syntax and date-based functionsAbbreviations
are only used for the AddRoadName
quest, so if this is left out, the abbreviations are not immediately neededCountryInfos
are only needed for certain quest types, could be left out at firstSo, the estimation for a MVP could be as little as 2 months for UI and 2 months for the core, so in total 4 months.
If Kotlin Native is chosen over Multi-OS-Engine, adaptions to the core would take 4.5 months, so in total 6.5 months.
This is not so unachievable anymore, especially if multiple people would be working on it. I also remember working on the app about half a year before I could release the first public version. So, if any iOS developer who is interested in it reads this but wouldn't want to stem this alone, give a shout!
Short notice: iOS is going to remove OpenGL for new iOS versions, which means that the cross platform library tangram-es (for rendering the map) will not work anymore. It is very unlikely that tangram-es will be updated any time soon to support Metal instead on iOS, so for iOS, another library would need to be found.
Can’t you considered this open source iOS app (GoMap) as the iOS equivalent of StreetComplete ?
Don’t know that much both projects but it seems to be very close.
Go Map!! is an equivalent of Vespucci, full scale OSM editor. See https://github.com/bryceco/GoMap/issues/240
See also https://wiki.openstreetmap.org/wiki/Editors and https://wiki.openstreetmap.org/wiki/Go_Map!! and https://wiki.openstreetmap.org/wiki/Vespucci
data types from the osmapi library need to be wrapped and instead own data classes must be used (1.5W)
The app currently uses the Java library Kryo for serialization. The library is stable and works without issues, but I am thinking about migrating to kotlinx-serialization-json, because
When migrating to kotlinx-serialization-json, it lends itself to define own data classes for OSM data because that library does not work with reflection but auto-generates the serializer/deserializer classes using a gradle plugin and this automation does only work for classes that are specially annotated, hence, must be defined in the source code proper, not in some external library.
Further, for some technical reasons I don't want to go into detail right now, to implement #2441 kinda requires or it is very much recommended to do that migration before that.
Summary:
Help wanted:
Most of the migration is kind of an easy mostly search&replace but very effortful refactor task. I added the data classes that shall be used already in the no-osmapi-data
branch. If there are any people who would like to help out, you are very welcome!
Here is some interesting insight from someone who is using Kotlin Multiplatform in his day job:
to make it easier to find: iPhone (sorry for a new comment, but I have no existing comment here to edit and notification seemed lesser evil than editing someones else post)
Edit: also Apple
The no-osmapi-data
branch is already merged and I updated that list https://github.com/streetcomplete/StreetComplete/issues/1892#issuecomment-686495406 after that.
This is just one one many many things that would need to be changed for an iOS port to be possible.
I was thinking about plans a bit and I am wondering whether things from
2.1 However, the following changes need to be made:
are worth doing right now. How likely is that work done now (without iPhone etc) is going to be useful and get us closer to potential iPhone version?
Is any of this things useful on its own, or is it just making things not worse on Android and being a small piece of work toward iPhone version?
Is it worth doing them just in case and to make iPhone version a tiny bit closer?
For example in
Logging in certain classes uses an Android framework. Should switch to an own implementation or wrap it in an interface (1.5W) SharedPreferences must be wrapped behind an interface so that UserDefaults can be used instead for iOS (1W)
it seems that creating intermediate interface should not be something horrible complicated. But does it make sense to do it right now, given that it will be a bit more confusing for people used to Android development?
Some things make sense, because they don't make the code more complicated. Some others would only make sense if one really started to work on an iOS port because it would make the code more complicated. I'd say, these things could make sense on their own:
- Logging in certain classes uses an Android framework. Should switch to an own implementation or wrap it in an interface (1.5W)
would make it possible to (also) log the logs to some place within the app, so that the log could be attached to crash reports and/or accessed by the user when asked about it.
- SharedPreferences must be wrapped behind an interface so that UserDefaults can be used instead for iOS (1W)
That would be cleaner anyway, in my opinion. Maybe it is two things:
LastEditTimeStore
MapLibre (ex Mapbox SDK) now supports Metal, so an iOS port would probably (need to) use MapLibre instead of tangram-es. This requres to
As tangram is not really developed further, it might be a good choice to change to using the maplibre SDK for Android too. Or - bluesky - use/create a map view that directly renders the OSM data.
You have my true respect not simply throwing away the implementation request and keep on evaluating!
Just to check:
Quest types use Android resources (for icon, title), these must be outsourced from the actual quest type definitions (1W) QuestAutoSyncer depends on Android location framework and must be wrapped (at least), other location-related stuff (1W) More/all constants defined in ApplicationConstants should be injected instead (1W) Controllers (etc.) use CopyOnWriteArrayList to manage listeners, must replace with something else that is not Java (0.5W) and experimenting with replacing Tangram by Maplibre
would it be also a good idea to do as separate tasks, done as improving Android version? And doing them as first steps, without plans for immediate continuation?
No, because it does not improve the code.
For people who want StreetComplete on iOS in the interim, take a look a this.
Additionally, @bryceco now parses the kotlin code to include some of the StreetComplete quests in GoMap!! but this parser relies on that the tag filter expression is at the usual place and has not no further logic added.
Originally posted by @westnordost in https://github.com/streetcomplete/StreetComplete/issues/3456#issuecomment-951822330
Which exists in: https://github.com/bryceco/GoMap/tree/master/src/Shared/Quests
I have already written some apps for IOS in Swift and as well tried some with cross-platform intents. As a result I would not recommend a complete cross-platform approach, but write at least the UI native. The core data and logic can then be integrated as a framework. IOS native with Swift and UIKit is not that complicated and can even be quite readable if you don't use Storyboards or Xibs, but write everything in code. To make things really readable (especially auto layout), some extensions to UIKit classes and some other base classes should be used. I could provide these. For map views it is not even necessary to use Apple's MapKit. I have written and can provide a MapView for OSM, which does not have Apple's unreliable caching mechanisms. You can check this in SwiftyMaps here on Github (though not very much documented) I don't know how far this topic has already developed, but if you are interested in this approach, please let me know.
@mr-elbe5 well, there's no "development" in this topic which I'm aware of. So feel free to write a "clone" application for iOS, if you like.
But I think your have to ask @westnordost if he is fine with using the same name. The default would probably to alter the name a bit to make it clear that it's not the same project :)
My limited experience working with cross-platform UI (React Native + Expo) has also been that you still have to write platform-specific code; the abstractions are leaky (e.g. for recording audio you will probably end up with different file types on each device. You thought you could avoid server-side transcoding? think again).
My gut says that if you're willing to accept a degraded experience on iOS, using kotlin multiplatform with a single code base would be less effort to maintain than writing native UI. Inversely, I suspect shared libraries + native UI will be less effort to get a polished experience on both platforms.
At the end of the day, it doesn't really matter in terms of what incremental steps to take towards making it a possibility: Separating the code into platform dependent/independent parts will be helpful for either approach.
Just to clear any misconceptions uttered above: Both in the MOE and in the KMM approach, the iOS UI is written natively with UIKit. The key difference between MOE (Multi-OS-Engine) and KMM (Kotlin Multiplatform Mobile) is that
I met with @mr-elbe5 and he showed me how he does the layouting purely with UIKit in code (no storyboards, no SwiftUI) with extension functions on UIViews in his projects. It looks all pretty swift. In my opinion, with SwiftUI not really production ready and maybe never will, plus with Storyboards being quite unflexible/horrific (in my experience), this is the way to go.
I took away from the meeting that the MOE approach should not be pursued further, because:
ViewController
s etc. code in Kotlin / Java. So, someone who would like to get involved here (writing UI code) would need to know both Java/Kotlin and iOS/Swift (and the possible quirks of MOE). The barrier for contribution seems a little high there.KMM on the other hand is already used by quite a few major companies, has excellent up-to-date documentation and the iOS-only code is written in Swift/Objective-C, so the same concerns don't hold for KMM. One open question from the meeting was how Kotlin native does memory management. The answer from the official FAQ is
Kotlin/Native provides an automated memory management scheme, similar to what Java or Swift provides. The current implementation includes an automated reference counter with a cycle collector to collect cyclical garbage.
With the framework decision settled to KMM (or at least not MOE), it is clear that
...to an eventual iOS port now?
This is not a kickoff insofar as the time I can invest into this myself will be severely limited, but each of the above points is a meaningful and sustainable contribution to an eventual iOS port. Especially point 1 and 2 are something that could be done with zero setup and independent of any other work towards this goal. I'd even propose a separate repository at first, so one doesn't need to take care how it can fit into the current setup of this repository. Eventually, it would be incorporated in this repo.
I have now tested the Android app (thanks to westnordost) and as far as I could analyzed some of the code. My conclusion is that an IOS app should be created independently from Android either under westnordosts's lead or as a completely independent app.
My reasons:
So from my side I will not be able to do all of this, but if somebody else takes the lead I will be happy to help with a sort of template-like test app to bring data to the UI, depending on the grade of generification. Meanwhile I will try to bring data from the OSM API to UI in a branch of my SwiftyMaps and hopefully this can be reused here.
One thing worth noting (and basically question to @westnordost ) - it is worth considering whether you would be fine with name "StreetComplete" used by app that is created independently and released by a different person.
Main risk here is that something similar to Ublock/Ublock Origin fiasco can happen ( https://en.wikipedia.org/wiki/UBlock_Origin#uBlock )
A clone of this app on iOS that shares no common code with this app should use a different name as there is no way such an app would ever reach the same feature set or even behave similarily as StreetComplete. Note though that such attempts failed twice before. Also note that neither the UI, the network requests, XML handling nor data storage1 would be part of a the shared code, because they are platform specific, so there is maybe a misconception what code would be shared. @mr-elbe5 FYI maybe this is of interest for you.
An iOS port can be developed iteratively in the sense as that only a few quest types are supported from the start and over time, the UI for more quests are added. When a quest that is already supported on the iOS port is extended (e.g. by adding another answer option: "Is this a self-service laundry?" -> [no] [yes] ... becomes ... [no] [optionally] [only] ), it is true that UI changes from then on need to be done on the iOS and Android app simultaneously. But this is by design: It ensures that all quests that are available on both platforms work the same and have the same logic.
It looks like mr-elbe5 has a different view on that matter than me, but let's - when required - open a topic in the discussions forum about it as this ticket should remain succinct and just outline the tasks that need to be done, see my previous comment.
1 only the data storage logic, not the data storage itself.
@westnordost wrote:
This is not a kickoff insofar as the time I can invest into this myself will be severely limited, but each of the above points is a meaningful and sustainable contribution to an eventual iOS port.
How about pledging on this?
Would we be able to just buy more time on this matter? It comes up pretty often as a request, so there's some demand. If I got just a buck for each time I got asked about that :'D
Well you could use https://bountysource.com/ or a similar service to collect bountries for issues like this one… if you want…
Stupid question: Wouldn't is be "simplest" (atm) to deploy a web-version? So iOS and tablet devices can calm the website and one can login?
Well you could use https://bountysource.com/ or a similar service to collect bountries for issues like this one… if you want…
Yeah, I was just wondering if that would be an option. There are a couple of services available. Not sure what kind of service would be appropriate for pledging goal on this for a German developer – so I didn't want to recommend a service.
Stupid question: Wouldn't is be "simplest" (atm) to deploy a web-version? So iOS and tablet devices can calm the website and one can login?
I don't think so. Web services would require a server able to handle the load. This increases the cost to run this project for no real benefit – as there's also a lot of developing time involved to convert an Android app to a web service.
However, you can run Android apps for example on ChromeOS in the browser – if this is a thing you're looking for.
I really don't want this ticket to dwelve into a discussion. That's what the discussions forum is for. This ticket shall just list what needs to be done and how it is/can be organized. I hide every post as off topic that is about something else.
There are various possible funding sources one could try and people have contacted me tentatively privately about the possibility to fund this. Maybe it would help if those organizations that are thinking about maybe funding or helping to fund this to state this publicly - but, I think the key necessary ingredient for an iOS port of StreetComplete is a knowledgable Swift/iOS developer that is willing to take a leading role in this effort. Then we can see if we can find funding for this, not the other way round. After all, we strive for committment to the project in that they are also willing to maintain it over time. Hence, why I wrote before that anyone who is (vaguely) interested in this as a programmer or even as a possible funding organization to give a shout here because if enough people are found, this could lead to a team effort and/or a common application for a funding. Certainly less of a hurdle than committing to doing it alone (though, you won't do it alone, iOS developers will work closely with developers of the core and the Android part anyway)
Might want to monitor https://github.com/icerockdev/moko-mvvm - would, when using MVVM (the app currently doesn't though), make it possible to put even the ViewModel
code into the common code. (Was mentioned in the Kotlin Multiplatform Mobile Beta Roadmap Update 2022-05-31)
Also, https://www.jetbrains.com/lp/compose-mpp/ looks very promising. Basically, the idea is that you write your UI in Jetpack Compose (similar to but more workable as SwiftUI, AFAIK) and that UI then works on both iOS and Android. This won't save any work as all the UI would need to be rewritten one way or another, but would somewhat cut the maintenance cost (as the Android UI code would be thrown away thereafter).
Edit: Uhh, though, I notice that iOS is not mentioned as a target for compose-mpp. Not sure why - is it really not supported and no plans to do so?
There seem to be people using it on iOS though: https://github.com/JetBrains/compose-jb/issues?q=is%3Aissue+sort%3Aupdated-desc+ios Interesting comment by the main developer: JetBrains/compose-jb#2048 (comment)
Compose for iOs is currently in an experimental stage and a lot of things just isn't implemented yet. We aware about issues with TextField, LazyList, etc, and we will fix them in the future.
@FloEdelmann Hmm, interesting. That could really be a game changer because that has the potential to making it much more painless to get to an iOS version: Instead of building the iOS UI from scratch, one could ("just") convert the current UI one by one to using compose-mpp and already use it in Android, knowing it can be used the same in iOS. Of course, Fragments, Activities etc. are still platform dependent, so what this mostly really does is replacing the Android layout XMLs with a Kotlin-based DSL that would be usable on iOS too.
JetBrains/compose-jb#2292
Though it seems it's already working? Albeit behind an experimental flag:
https://github.com/JetBrains/compose-jb/blob/a018ac802adea8572fe5e5b49d892c5126801fda/experimental/examples/falling-balls-mpp/build.gradle.kts#L165
Ctrl+F for uikit
in that file, it doesn't look like you need much iOS-specific setup.
All that said, I'm guessing it's in a similar situation to Compose for Desktop, maybe trailing by a few months—if you want to use the same Material Design components as on Android (rather than draw your own), you're going to have to wait. (If my experience with Compose for Desktop is anything to go by, the components aren't actually multiplatform anyway, they just have the same name and similar behaviour. nope)
@YoshiRulz does that mean that one has to implement the UI for each platform separately anyway? Just for example, the UI to input the capacity of bicycle parkings?
On a closer look, that sample project appears to have the main composable in common code, so I was mistaken about that. But I'm sure you could make actual
/expect
abstractions if not.
https://blog.jetbrains.com/kotlin/2022/10/kmm-beta/ https://android-developers.googleblog.com/2022/10/announcing-experimental-preview-of-jetpack-multiplatform-libraries.html?m=1
And a well known german news site announcing this beta with some explanation: https://heise.de/-7304527
@westnordost What's next after java.time
? Did you have a list of JVM/Android APIs in mind, or maybe a third-party library that can be ported to Kotlin Multiplatform? You mentioned your countryboundaries and osmfeatures libs but IMO it's better to do first-party code last.
In my personal projects, I'd at this point move the test code to common and add expect
declarations until it compiled. From https://github.com/streetcomplete/StreetComplete/issues/1892#issuecomment-1042296087 I gather you wanted to switch to Multiplatform and add the common module; if you or someone else familiar with the build system could do that now, I'll evaluate how much expect
/actual
noise will be required for moving tests to common.
There is no definitive list, but one thing on my tally is that all *Controller
classes that are observable use java's CopyOnWriteArrayList
to keep the list of listeners in a thread-safe way. This should be replaced with for example a synchronized (or "copy on write") HashSet. An to not litter synchronized
everywhere, could make that a (thin) wrapper class around HashSet called Listeners or something.
Regarding your proposed next steps: I agree that porting the libraries to Kotlin is something that would only be worthwhile if another non-Java project would like to use them at this point. Regarding reconfiguring the build system for multiplatform - that could be done, but on the other hand, there are some known needed refactorings still to do, e.g. at least https://github.com/streetcomplete/StreetComplete/issues/3597#issuecomment-1107931316 (for which I do not know the status of, it could be that @matkoniecz started on it already, I don't know). Also, I was asking myself if the common test code can/should depend on kotlin.test rather than JUnit so it could be moved to common, but on the other hand, a lot of it uses Mockito as a mocking framework and I am not aware of any pure Kotlin replacement for Mockito.
I run a team of mobile developers who are into both iOS and Android. Would love to give this one a try.
That's great to hear!
Let me summarize for you the current state of affairs:
A possible iOS port should be developed using Kotlin Multiplatform Mobile so that as much code can be shared as possible. (Yes, the amount of sharable code is considerate. Already 2-3 attempts at creating an iOS port from scratch were abandoned because they all underestimated the sheer size of the project.) In a nutshell: Application logic shall be implemented in pure Kotlin without direct dependencies to Java or Android. This code can then also be used for the iOS part. Currently, most of that code is already free of such dependencies.
The next self-contained steps (I can think of) in that regard are, for which PRs are welcome:
small Controller classes use Java's done by @neonowy in #5346java.util.concurrent.CopyOnWriteArrayList
to store their listeners (observer pattern) which need to be replaced to get rid of the dependency to Java. (See https://github.com/streetcomplete/StreetComplete/issues/1892#issuecomment-1286712656)
big At some places java.util.Locale
and related (e.g. java.text.DateFormatSymbols
) are used for different things which need to be replaced. This might be a bit difficult because as far as I know, there is no multiplatform replacement for Locale (yet?). So, either the Locale functionality used in different places needs to be re-implemented or someone would need to create a Kotlin multiplatform library that is a 1:1 replacement of Locale
. Either way is going to be a considerate amount of work, I think.
small done by @neonowy in #5307PolylinesSerializer
uses various Java *Stream
classes which need to be replaced. Not sure if there is an easy replacement (but there should, anything that deals with I/O needs something like this, and e.g. ktor is multiplatform, as far as I know)
medium Some DAO classes use done by @neonowy in #5357SharedPreferences
(Android's persistent key-value store) to store certain data. That class should be wrapped in an interface so that it can be used independent of platform. (There's also multiplatform-settings library but not sure if it is worth it, considering it should just be some 100 lines of code)
medium Some controller classes use the Android logger to log stuff. This has to be replaced either with a thin multiplatform wrapper (see also #3597) or use a multiplatform logging framework such as Napier, Kermit, Kodein-Log, or others .... The app doesn't log that much though, so an elaborate logging framework might be over the top. done by @neonowy in #5335
big the app depends on the Java library osmfeatures
(made by me). It needs to be migrated to Kotlin multiplatform library (or ported to native and wrapped).
big the app uses the Java library osmapi
(made by me). It must be replaced or migrated to multiplatform somehow... maybe another approach is better with some auto-generated API through a description of the API (maybe via swagger or similar? -maybe check this out) . Or, could this be done with retrofit? If yes, maybe it could be done with Ktorfit
none / wait the app uses the YAML parser com.charleskorn.kaml
which is currently JVM only, however it looks like there is some work in progress to make it work on native, too. Alternatively, this could be one chance to get away from YAML to e.g. TOML or JSON for config files (we use only very basic YAML features anyway, TOML would be more than enough)
medium the app uses the Java library OpeningHoursParser
to parse opening hours (, collection times, etc.). This needs to be wrapped and replaced for the iOS app. Not sure if there is a library for this, but GoMap!! also parses opening hours, so bryceco needs to have some way to do this. The linked library is created with JavaCC, so even the EBNF-like notation is Java-specific. For a Kotlin multiplatform version of such a parser, maybe ANTLR or more specifically, https://github.com/Strumenta/antlr-kotlin could be used
medium migrate also the unit tests to the shared module. Many tests use Mockito, which would need to be replaced with a mocking-library that isn't Java specific, such as MockingBird, Mockative or MockMP. (Needs research which mocking library is the best choice)
big (finally) the quests themselves have some dependencies to Android. This is currently convenient, so I would not break that up until the other things that block an iOS port are done beforehand. (Also I have to think about that before how to exactly do this best)
(If I see there is some commitment, I can also write these into tasks with more precise descriptions, rough time estimations, the github kanban-like board etc. later)
The Android UI code is currently done with layout XMLs. In KMM, by default, one would write the iOS specific part (mostly: the UI) in Swift like in other iOS projects and access the application logic as a library. This means that the entire UI for iOS has to be re-written from scratch and also - importantly - having to be maintained separately from the Android UI. An alternative to this is Compose Multiplatform, built on top of KMM, currently in alpha. It is a fork / extension of Android's Jetpack Compose, a UI framework comparable to SwiftUI. In Compose Multiplatform, you write the UI once in shared code and it renders on both Android and iOS. This still means that the UI needs to be written from scratch, however
in the end, there will only be one UI implementation, not two. This makes a huge difference. To expect a long-term commitment of any code contributors to also maintain their contributed code would be illusory. And as the app is not backed by any company or organization, the time the main developer (that's me) can put into app maintenance is severely limited. Maintaining two UI implementations is going to be double as time-consuming as maintaining one, i.e. not really viable if I remain to be alone.
since Compose can apparently be integrated seamlessly into Android XML layout UI code and vice-versa (same with UIKit and SwiftUI, but this is not relevant here), a migration from Android XML-based UI code can be done step by step. This, too, is a huge plus as it enables different contributors to contribute their piece and come and go without one contributor in particular committing (alone) to a huge undertaking that may work or may fail entirely. I've learned that such an iterative model is key to success in an open source project where you can't oblige people to see anything to the end like it would be the case for employer-employee relationships.
The main downside of Compose Multiplatform is that we'd have to replace working code and that it is still in alpha. Working with cutting edge technology usually isn't pretty because the environment is changing under your feet and certain things don't work or only with messy workarounds. Additionally, Compose Multiplatform is not the silver bullet for the UI, as many Android/Java-only dependencies are used in the UI which would need to be replaced with an appropriate replacement on iOS. (E.g. the map renderer, the QR code generator, the physics simulation in the profile screen, ...).
However, Jetpack Compose on the other hand is stable and has an almost 1:1 API as its Multiplatform brother, so "just" migrating step-by-step to Compose doesn't seem too risky. Also, as the list in the previous heading shows, there are enough other things to do (before) anyway, so when that is done, Compose Multiplatform and the environment around it matured more.
In any case, I am currently familiarizing myself with the technology, so I might be able to say more about that in the future.
, there are many small tasks that can be done to further advance towards an eventual iOS port. These do not require a heavy or long-term commitment and can be included in the project as contributions just when they are done each. I know it can be somewhat demotivating to want to contribute to a project a huge project and then see that it will never be merged (because it becomes bigger and bigger along the process, a neverending construction site). For the above tasks, this is not a concern, as they are all each modular, self-contained and once merged live in the same repo and branch as the original Android version.
Working with and getting to know new (Kotlin Multiplatform Mobile is in beta) or even cutting edge technology (Compose Multiplatform is in alpha) can be a motivation on its own. Especially, I find the prospect of (learning how to use) the two technologies combined together somewhat appealing also from a business perspective, as it may potentially cut the cost of developing an Android + iOS app to almost half.
Kotlin Multiplatform (KMP) is making progress: https://blog.jetbrains.com/kotlin/2023/11/kotlin-1-9-20-released/ https://blog.jetbrains.com/kotlin/2023/11/kotlin-multiplatform-stable/
sum up from a german IT new site: https://www.heise.de/news/Kotlin-macht-Ernst-mit-der-plattformuebergreifenden-Programmierung-9352485.html
A roadmap for 2024 was introduced yesterday: https://blog.jetbrains.com/kotlin/2023/11/kotlin-multiplatform-development-roadmap-for-2024/
Edit: Planning for an iOS version continues in #5421
See also the last comment on this ticket
Quite a few times, it has been requested that an iOS version of this app is made available. This ticket shall serve as an explanation why this isn't possible but also as an entry point for why it is perhaps possible after all, but with enormous effort. So if you are an iOS developer and interested in creating an iOS version, also read this.
It's not possible
StreetComplete is developed as a native Android app and iOS is a completely different platform. There is no compatibility at all. Usually, if you see an app that is both available for Android and iOS, it is either not native (for example, just a website being displayed within an app or using a cross-platform framework such as ReactNative) or you are looking at two completely different applications, likely developed by two teams. This is my experience as a professional app developer.
Maybe it's possible
So, this is interesting if you are an iOS developer yourself. It is not planned from my side to do this.
Kotlin Multiplatform Mobile
This app is written in Kotlin, a modern programming language that is quite similar to Swift. Originally, Kotlin was built to run on the JVM, but by now, it can be transpiled into JavaScript, and with Kotlin Native, also to machine code, just like Swift. This makes it possible to write iOS apps with Kotlin. Thus, Kotlin code of this project that is not dependent on any Java library (Http library etc) and also not dependent on the Android platform (UI, sensors, persistance management etc) could be used 1:1 in an iOS port of this app. Such "pure" Kotlin code would be put into a common module that is shared between the iOS and the Android app. However, not a big percentage of the total code in this project is such pure Kotlin code that has no dependencies to any other Java or Android dependencies. Most of the iOS app would still need to be written from scratch, in Swift or better in Kotlin, if possible. On the other hand, some of the code that is currently dependent on some Java library or Android dependency could be changed to not be dependent on it directly anymore but on a wrapper interface. Then, only that wrapper would need to also be implemented for iOS.
Multi-OS Engine
The MOE is a little different approach. So, the JVM of Android is called ART and is open source. On Android, we write apps that run within this virtual machine provided by the Android system. For iOS, there is no such virtual machine, apps run natively. But, what we could do, is to write an app that comes bundled with the ART virtual machine and does nothing else than to load the provided JVM bytecode. This is the approach of MOE. In other words, ART is automatically bundled in the app so that one can write an iOS app in the Java environment, making use of the Java ecosystem and libraries. iOS platform dependencies are accessed over an interface provided by MOE. The difference to the Kotlin Native approach is, that Kotlin code that depends on Java libraries can also be moved to the common module that is shared between the iOS and the Android app. The only things that cannot be shared is code that is dependent on the Android platform, such as UI or currently persistance with SQLite (because it uses Android dependencies). (see https://github.com/streetcomplete/StreetComplete/issues/1892#issuecomment-1042296087)