Hi, new to KMM. Wondering what the recommended app...
# multiplatform
s
Hi, new to KMM. Wondering what the recommended approach to navigation is for a Android/iOS app target? Is there some kind of library that can be used to handle navigation on both platforms, or is it better to just handle navigation independently on each platform (since navigation is related to UI, and it's better to write UIs independently)?
a
Since Navigation is more a UI thing, I think it would be better to handle that outside KMM
k
I would agree with Alejandro, probably natively handled. You could handle some of the logic in KMM, like if you have a lot of screens or certain cases in how you move between screens, you could have a common State Machine for navigation. I would say it depends on the complexity of the navigation.
l
If you do want something common, #decompose offers a pretty good navigation library.
k
❤️ 1
h
If you want to write native UIs, I would instead use androidx compose navigation and SwiftUIs built-in "navigation"/NavigationView.
p
To me, navigation is really a state and therefore a business logic thing and absolutely not a ui thing. A ui thing is navigation animation.
c
Yeah, I’m firmly with @Paul Woitaschek on that one. In my experience, the navigation pattern that Android has pushed for so many years has made app development way more difficult than it needs to be. Navigation should live above the application (like browser URLs) or at the application root, intentionally separate from any UI, and then the UI can observe URI changes and perform animations in response to it. Having navigation so tightly coupled to UIs makes things like deep linking and redirects quite difficult compared to a state-based router. To that end, I’m not aware of any navigation libraries that work well with both Android and iOS, because pretty much everything out there right now has copied the Androidx Navigation pattern and coupled itself unnecessarily to the UI. I’m currently working on a pure-URI based router based on #ballast MVI state management, which I’m actively using in Android and JS/Web apps, but it’s far from production ready and I haven’t even considered iOS navigation with it yet.
l
decompose does a good job of decoupling from the OS libraries. I chose it over moko-mvvm for my projects largely because it offers the ability to expose the navigation as a state. You then observe the navigation state in your SwiftUI, Compose, or whatever else and choose which screen to render. Decoupling from platform libraries also helps with testing. I can look at the state in my tests.
c
I personally didn’t care for Decompose when I tried to use with my a Compose Desktop app. I found it’s API a bit too cumbersome and over-architected, it was very clearly designed first for Android rather than multiplatform, and it’s lifecycles and core APIs were not designed to work with coroutines, which consistently made things difficult for me. What I really wanted was a router that didn’t care about lifecycles and used simple String URIs for destinations rather than dedicated configuration objects that were coupled to the Decompose library, which is why I started working on my own. That’s not to say Decompose isn’t a good library or that you should avoid it; it’s very popular and a lot of folks like using it, so if it works for you, by all means use it! You’ve got a good community around to support you with it. It just didn’t work for me with the way I wanted to architect my app, and it’s worth understanding the pros/cons of any navigation library, or even deciding if you need one at all (relying on standard platform navigation for each app instead of introducing a new framework in your common code)
l
That’s fair. I found the Value type kind of annoying since it isn’t necessarily integrated with other libraries. I found that using Flows instead worked much better, but by that point, using decompose was more of a formality. One could use a similar idea of navigation using a state, but using a MutableStateFlow instead, without bringing in a library for state management.
a
A multiplatform navigation library's design is heavily affected by a number of factors. 1. The navigation state must be persistent on Android and potentially on iOS too. 2. It must be possible to handle configuration changes and process death on Android (and potentially on iOS too). 3. It must be possible to use any UI framework on any platform. Because of that, there is Value instead of Flow - it's interoperability with Swift is excellent. Also because of that the API is not compose-first but platform-agnostic. Yet using coroutines is very straightforward. Components are lifecycle-aware, so it's very easy to create a local CoroutineScope. And one can expose a StateFlow instead of Value, just convert it with an extension function. There are benefits of using Value instead of Flow though: 1. Testing is much easier. 2. You never skip frames due to random re-dispatches on the main thread. 3. One can use Reaktive instead of coroutines.
Compile time safety is a top priority for Decompose, that's why URLs are not used for navigation and one may find it boilerplate-ish or complicated. It's totally fine and one may prefer another library for whatever reason. 😀
s
This almost escalated beyond my understanding 😄 , but thanks for the suggestions here, people. I'll evaluate the discussions and choose what fits my needs.
a
@Casey Brooks is the navigation library you are authoring open source? Is there a link I can look at?? or better, contribute to it??
c
It’s not officially published yet, but the source is available on the features/navigation branch of the Ballast repo, and a snapshot build (2.1.1-SNAPSHOT) is available in the Maven Central Snapshot repo
Copy code
repositories {
    mavenCentral
    maven(url = "<https://s01.oss.sonatype.org/content/repositories/snapshots>")
}
dependencies {
    implementation("io.github.copper-leaf:ballast-core:2.2.1-SNAPSHOT")
    implementation("io.github.copper-leaf:ballast-navigation:2.2.1-SNAPSHOT")
}
The main functionality is there, but I’m not quite happy with the DSL yet, so feedback on how it could be improved would be much appreciated. I’d also be interested in moving the URL-parsing away from
io.ktor:ktor-http
, either to a lighter MPP library if one exists, or just actual/expect. It doesn’t have any documentation (which kinda needs to wait until the DSL is figured out), but you can take a look at this site I’ve been using this on to get an idea of how to use the library, or join us over in #ballast for more help
1101 Views