When starting development of a mobile app one of, if not the, most important decision to make is what stack you choose to use for your app. Every stack forces you to make some sort of tradeoff whether it is an increase in development time (vanilla native) or a decrease in quality of the product you create (cross-platform frameworks). When faced with the same decision we tried most of the possible mobile stacks and frameworks for our new app (VitraCash) and we decided on using a unique stack (KSJ) that manages to achieve the best of both sides of the spectrum, high quality and short development times, Kotlin Multiplatform, SwiftUI and Jetpack Compose.
An explanation of the Stack
While this combination of frameworks can be used in a variety of ways we settled on writing shared code, with KMP, that contains the networking, business logic, and view logic code. The only code that we would then write natively would be the UI code therefore giving the app a high quality native feel while letting us share all of the complex code between both platforms causing a significant decrease in development time. We chose to use SwiftUI and Jetpack Compose for the UI code because they are both new declarative UI frameworks which helps us keep the two native code bases as similar as possible while still keeping the native feel of both platforms to the apps.
We have yet to encounter any significant drawbacks of this stack though every framework have caused a few minor inconveniences. The biggest issue is that because all three frameworks are not yet widely spread finding resource which means that if you encounter a bug or want to implement a more advanced feature you are most likely on your own and will have to write a decent bit of code yourself in cases where you would often find open source libraries to lessen your work load, though that is something which will get significantly better as more and more people start adapting theses frameworks.
With SwiftUI the only real obstacle we encountered was programatic navigation as unlike UIKit where a NavigationController can be controlled programmatically in SwiftUI one always has to use a NavigationLink, which is a button of sorts which when pressed sends the user to a specified screens (more details coming in another post)
With Kotlin Multiplatform we found that there are a lot of frameworks one can choose from, a lot of which either don't work at all or start causing problem when used at scale, so I recommend the following: Ktor (Networking), Koin (Dependency Injection) and SQLDelight (Client-Side Database for Caching).
With Jetpack Compose we have yet to encounter any major issues, but I will recommend that one sticks to the default libraries android offers for most features, especially Navigation, even though there are other libraries out there in my experience it is not worth using them even if you find that they are more convenient.
With everything considered I have yet to find another stack that close to rivaling KSJ, the feel of the app is native and smooth because the UI code is in fact native and all the complex code is shared causing a significant decrease in development time while causing such a minimal performance decrease to vanilla native development that it is entirely negligible on every modern device. You essentially get a native app with a 40-60% decrease in development time depending on the complexity of your business logic.
For brevity, I am going to skip over most of the precise implementational details
For Android nothing changes, you use the shared code like you would any normal library with gradle. For iOS, you have to compile the shared code into a native library that you can then integrate it into your xcode project, though I find the default build code that KMP provides to be lacking as it sometimes causes issues especially when switching between using the Simulator and building for an actual device (better build task).
As mentioned above we use Ktor Multiplatform HttpClient which, in my opinion, is by far the best networking library for KMP.
As is necessary in almost every app you will end up having to cache some thing client side in case of networking issues and to decrease the traffic you are sending to your server. As mentioned above we use SQLDelight for persistent and I do highly recommend it.
While debugging for iOS and Android specific code obviously stays the same as you are using native code. Android Studio supports Kotlin debugging out of the box but for Xcode you have to install xcode-kotlin to debug your KMP code while using it in your iOS app.