- Use this repository as a template when creating a new repository for your project
- Rename the project (don't forget to change
rootProject.nameinsettings.gradleandidandAppNameinApplication.kt) - Rename iOS project - you can use prepared script, for more info see the iOS readme
This repo contains our template for multiplatform mobile project. Both Android and iOS
implementations
are present with shared modules containing all common business logic organized in Clean
architecture.
The project contains four sample screens:
- one with native UI and native view model (for Android Compose UI and view model in Kotlin, for iOS SwiftUI and view model in Swift)
- second one with native (Compose and SwiftUI) UI and shared view model
- the third one with shared Compose Multiplatform UI and shared view models
- and the last one with shared Compose Multiplatform UI and shared view models and also * compose mutliplatform navigation*
Clean (common modules) + MVVM (platform-specific modules) architecture is used for its testability and ease of modularization. Code is divided into several layers:
- infrastructure (
Source) - data (
Repository) - domain (
UseCase)
Shared modules in general handle networking, persistence and contain UseCases which bridge platform specific code with common code.
There is :shared:core that combines feature modules and core and generates XCFramework for iOS
and is the main module imported in android modules.
:shared:base is a module containing all the base and common classes needed in feature modules.
Structure inside each module is organized with Clean architecture in mind to several layers of
abstraction where everything in domain or data layer is marked as internal to prevent confusion.
The whole project relies heavily on dependency injection
Android code is separated into several feature-modules with android:app module providing
navigation root and android:shared module containing shared android code like common components or
values. Following standards the Android-specific modules use MVVM architecture where ViewModels use
UseCases as gateway to shared model layer (in case you use native view models).
- More info in the iOS readme
As mentioned above, there are three options for how much code you want to share between platforms.
If you choose not to share view models neither UI, you can go ahead and
delete samplesharedviewmodels and samplecomposemultiplatform modules in both shared
and android and samplecomposenavigation only in shared and create own repositories, use cases,
sources, ... according to what you find in the :shared:sample module and UI and view models
according to :android:sample. You can also remove compose multiplatform plugin from
libs.versions.toml.
If you choose to share view models, but use native UI, you can delete
the samplecomposemultiplatform module in both sharedand android and samplecomposenavigation
only in shared. You can also remove compose multiplatform plugin from libs.versions.toml.
Refactor base classes that you will need: move samplesharedviewmodel/base files in
:shared:samplesharedviewmodel to the :shared:base module (from commonMain as well as iosMain
and androidMain) to have base classes you can extend. Also in iOS project move
SampleSharedViewModel/Toolkit to UIToolkit. Then you can write your shared view models in the
same way as the SampleSharedViewModel is written and used (especially check the usage on iOS with
helpful extension methods).
If you do not want to use shared view models inside SwiftUI views, you can remove the expect from
BaseScopedViewModel (and the actual class), the
whole BaseIntentViewModel interface and the whole SwiftViewModelCoroutines, to simplify the base
view model.
If you go all out and decide to share both UI and view models, take inspiration
from SampleComposeMultiplatformScreenViewController when calling you view from the swift code. For
Android there are no changes needed, see in :android:samplecomposemultiplatform for yourself.
You can move the classes in ui/test to shared module.
Starting with Compose multiplatform 1.7.0 (in combination with androidx navigation-compose and
compose material-navigation libraries) we can use Material navigation in multiplatform. You can
see a minimal example in :shared:samplecomposenavigation.
Beware: Using libraries mentioned above breaks swipe back navigation when using compose multiplatform views inside UIKit navigation on iOS, so in case you want it working, downgrade
compose multiplatformto 1.6.11 and removeandroidx navigation-composeandcompose material-navigationlibraries.
- Create a new module and copy
build.gradle.ktscontent from one of the existing modules, changenamespaceand dependencies on other modules as needed - Add dependency to
settings.gradle.kts,build.gradle.ktsof:shared:coreand.kmm()inKmmConfiginbuild-logic - Add DI module to
Modulein:shared:core
There are UI tests prepared for all three screens in android/app/androidTest. You can take
inspiration and write tests for own screens with prepared structure and extensions.
Koin supports Kotlin Multiplatform and it's pure Kotlin project. Each module (including all Android feature modules) has it's own Koin module. All modules (including common module) are put together inside platform specific code where Koin is initialized.
We are using DI library Factory.
Accessing network is usually the most used IO operation for mobile apps so Ktor was used for it's simple and extensible API and because it's multiplatform capable with different engines for each platform.
All strings in the application are localized and shared with the iOS team
via Twine. Strings are stored in the twine/strings.txt file.
TwinePlugin then generates appropriate strings.xml files from the mentioned strings.txt file.
When modifying strings.txt it is required to comply with the specified syntax and to pull/push all
the changes frequently
Error messages are shared via Moko Resources, so
that we can use the strings in the shared code and avoid duplicities when converting errors to
string messages. Error strings are stored in the twine/errors.txt file. Gradle task
generateErrorsTwine first generates strings.xml files from errors.txt and then gradle task
generateMRCommonMain generates MR class that can be used in the common code.
Jetpack Compose is the go to for Android UI nowadays.
We recommend going with SwiftUI, unless you want to for some views or screens use Compose Multiplatform (below)
Compose Multiplatform (from Jetbrains) is still young, but you can try it out and for some simple screens (or maybe whole simple projects) it might be the right choice. It can save a lot of time since each view will be written only once and used on both platforms.
- More info in the iOS readme
