D-KMP Architecture official sample: it uses a shared KMP ViewModel and Navigation for Compose and SwiftUI apps.

Overview

D-KMP architecture - official sample

This is the official sample of the D-KMP architecture, presenting a simple master/detail app, for Android, iOS and Desktop.
(the Web version will be added at a later stage, when "Compose for Web" becomes more mature)

For more info on the D-KMP Architecture, please read the relevant Medium article.

Note: in order to run the sample you should use the latest Android Studio Canary build.

Key features of the D-KMP architecture:

  • it uses the latest declarative UI toolkits: Compose for Android and SwiftUI for iOS
  • it fully shares the ViewModel (including navigation logic and data layer) via Kotlin MultiPlatform
  • coroutine scopes are cancelled/reinitialized automatically, based on the current active screens and the app lifecycle (using LifecycleObserver on Android and the SwiftUI lifecycle on iOS)
  • it implements the MVI pattern and the unidirectional data flow
  • it implements the CQRS pattern, by providing Command functions (via Events and Navigation) and Query functions (via StateProviders)
  • it uses Kotlin's StateFlow to trigger UI layer recompositions

Data sources used by this sample:

other popular KMP libraries for connecting to different data sources:

Instructions to write your own D-KMP app:

If you want to create your own app using the D-KMP Architecture, here are the instructions you need:

SHARED CODE:

View Model

  • πŸ› οΈ in the viewmodel/screens folder: create a folder for each screen of the app, containing these 3 files (as shown in the sample app structure above):
    • screenEvents.kt, where the event functions for that screen are defined
    • screenInit.kt, where the initialization settings for that screen are defined
    • screenState.kt, where the data class of the state for that screen is defined
  • πŸ› οΈ in the NavigationSettings.kt file in the screens folder, you should define your level 1 navigation and other settings
  • πŸ› οΈ in the ScreenEnum.kt file in the screens folder, you should define the enum with all screens in your app
  • βœ… the ScreenInitSettings.kt file in the screens folder doesn't need to be modified
  • βœ… the 6 files in the viewmodel folder (DKMPViewModel.kt, Events.kt, Navigation.kt, ScreenIdentifier.kt, StateManager.kt, StateProviders.kt) don't need to be modified
  • βœ… also DKMPViewModelForAndroid.kt in androidMain and DKMPViewModelForIos.kt in iosMain don't need to be modified

Data Layer

  • πŸ› οΈ in the datalayer/functions folder: create a file for each repository function to be called by the ViewModel's StateReducers
  • πŸ› οΈ in the datalayer/objects folder: create a file for each data class used by the repository functions
  • πŸ› οΈ in the datalayer/sources folder: create a folder for each datasource, where the datasource-specific functions (called by the repository functions) are defined
  • βœ… the datalayer/Repository.kt file should be modified only in case you want to add an extra datasource



PLATFORM-SPECIFIC CODE:

Android

Schermata 2021-06-26 alle 16 54 32

Schermata 2021-06-26 alle 17 03 13

  • βœ… the App.kt file doesn't need to be modified
  • βœ… the MainActivity.kt file doesn't need to be modified
  • The composables are used by both Android and Desktop apps:
    • πŸ› οΈ the Level1BottomBar.kt and Level1NavigationRail.kt files in the navigation/bars folder should be modified to custom the Navigation bars items
    • βœ… the TopBar.kt file in the navigation/bars folder doesn't need to be modified
    • βœ… the OnePane.kt and TwoPane.kt files in the navigation/templates folder don't need to be modified
    • βœ… the HandleBackButton.kt file in the navigation folder doesn't need to be modified
    • βœ… the Router.kt file in the navigation folder doesn't need to be modified
    • πŸ› οΈ in the ScreenPicker.kt file in the navigation folder, you should define the screen composables in your app
    • πŸ› οΈ in the screens folder: create a folder for each screen of the app, containing all composables for that screen
    • βœ… the MainComposable.kt file doesn't need to be modified

iOS

Schermata 2021-06-26 alle 16 53 55

  • πŸ› οΈ the Level1BottomBar.swift and Level1NavigationRail.swift files in the composables/navigation/bars folder should be modified to custom the Navigation bars items
  • βœ… the TopBar.swift file in the composables/navigation/bars folder doesn't need to be modified
  • βœ… the OnePane.swift and TwoPane.swift files in the composables/navigation/templates folder don't need to be modified
  • βœ… the Router.swift file in the composables/navigation folder doesn't need to be modified
  • πŸ› οΈ in the ScreenPicker.swift file in the views/navigation folder, you should define the screen composables in your app
  • πŸ› οΈ in the views/screens folder: create a folder for each screen of the app, containing all SwiftUI views for that screen
  • βœ… the MainView.swift file doesn't need to be modified
  • βœ… the App.swift file doesn't need to be modified
  • βœ… the AppObservableObject.swift file doesn't need to be modified

Desktop

Schermata 2021-06-26 alle 16 54 15

Schermata 2021-06-26 alle 17 03 13

  • βœ… the main.kt file doesn't need to be modified
  • The composables are used by both Android and Desktop apps:

Web (not yet implemented)

  • Compose for Web is still at a very early stage. We'll give it a bit more time to mature before publishing an app. The web version of SqlDelight (the most popular local database for Kotlin MultiPlatform) is also at a very early stage, as currently the database cannot even be saved persistently. It might take until the end of 2021 before it makes sense to work to a proper Compose for Web app.
Comments
  • iOS Native App

    iOS Native App

    Thanks for this project - I love the idea of the business logic and view models in the Kotloin shared layer.

    I am concerned about the iOS application - it does not feel like a native application due to the navigation style being employed. There are no animations. Is this by design? Can we use this architecture with the regular iOS Navigation, so it feels completely native?

    opened by adesugbaa 10
  • App not working for android < 26.

    App not working for android < 26.

    dependencies { coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.0.9") }

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
        // Flag to enable support for the new language APIs
        isCoreLibraryDesugaringEnabled = true
    }
    
    
    This is necessary as the app crashes in lower API versions due to as per https://developer.android.com/studio/write/java8-support#library-desugaring
    
    java.lang.NoClassDefFoundError: Failed resolution of: Ljava/time/Instant;
    at kotlinx.datetime.Instant.<clinit>(Instant.kt:93)
    at kotlinx.datetime.Clock$System.now(Clock.kt:17)
    
    Due to GetCountriesList.kt
    Line 13 -> val nowUnixtime = Clock.System.now().epochSeconds
    
    opened by raghavpai 5
  • FAILURE: Build failed with an exception.

    FAILURE: Build failed with an exception.

    • What went wrong: Please initialize at least one Kotlin target in 'shared (:shared)'. Read more https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#setting-up-targets

    • Try: Run with --info or --debug option to get more log output. Run with --scan to get full insights.

    • Exception is: org.gradle.api.GradleException: Please initialize at least one Kotlin target in 'shared (:shared)'. Read more https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#setting-up-targets

    How to solve this problem? i'm use AS Arctic Fox Canary 14.

    Thank you

    opened by irfanirawansukirman 4
  • Ios could not see getIosInstance()

    Ios could not see getIosInstance()

    I am trying to get work the repo. It is OK for Android and desktop, but in IOS I couldnt get DKMPViewModel by using getIosInstance()function. When I try with another simple class, I could reach the class and its functions, but after using Factory, ios could not reach the content. Any idea?

    opened by mehmetakify 2
  • Some doubts

    Some doubts

    Hello, excellent initiative.

    Could you give me any tips?, I have the following problems:

    When I click on run desktop, nothing happens image

    Codes are hidden after gradlew sync image

    opened by samucati 2
  • only one AppState may make performance issue?

    only one AppState may make performance issue?

    in the example, there is only one AppState, any ScreeState change make AppState change, and make the top level widget recompute. may this cause performance issue?

    opened by jiqimaogou 2
  • the architecture of D-KMP may be too complex?

    the architecture of D-KMP may be too complex?

    if I just write a network request and update the UI. D-KMP has so many concepts:

    1. Events.kt
    2. KMPViewModel.kt
    3. StateManager.kt
    4. StateProviders.kt
    5. StateReducers.kt
    6. Repository.kt

    and the relation between these concept is also complex. I think these are hard to maintain.

    image

    can you simple the architecture of D-KMP, make more less concepts, and less relationship between these concepts.

    opened by jiqimaogou 2
  • Could not initialize class org.jetbrains.kotlin.com.intellij.pom.java.LanguageLevel

    Could not initialize class org.jetbrains.kotlin.com.intellij.pom.java.LanguageLevel

    I have a problem when building, very similar to this one: https://stackoverflow.com/questions/66945802/installing-kotlin-jupyter-e-java-lang-noclassdeffounderror-could-not-initiali

    I haven't been able to solve it yet.

    I am running on 2020.3.1 Android Studio on a ARM Mac (M1), maybe that could cause the problem.

    opened by schrulnz 1
  • [Question] Architecture and implementation details

    [Question] Architecture and implementation details

    Hi!

    First, thank you for the huge amount of work you put in defining a neat and future-proof architecture, and for making it publicly available. I've been waiting for something like this for months.

    I have several questions about it (some of it may be exclusively related to Compose/SwiftUI as I'm quite new to native development):

    • Navigation:

      • How would you implement a second layer of navigation? e.g. A layer for onboarding unauthenticated users and another for logged-in users.
      • How would you handle actions depending on a screen's lifecycle? e.g. Doing something when the screen is rendered. Should lifecycle hooks be part of the architecture or should Compose/SwiftUI hooks be used to achieve this kind of action? e.g. A LaunchedEffect hook calls a function defined in the shared module
    • State:

      • Do you think this architecture is compatible with any kind of local cache as a single source of truth for the state? e.g. Apollo HTTP/Normalized GraphQL cache
      • If so, would you implement the caching behaviour inside the runtimecache or the localdb directory?
    • General:

      • Don't you think some of the unchanged files included in the sample should be upstreamed and packaged in a multiplatform library or some kind of DSL?

    If it helps, here's more information about what I'm trying to build: https://github.com/apollographql/apollo-android/issues/3106

    Thanks in advance for your time!

    opened by ajacquierbret 1
  • Plans to include web version

    Plans to include web version

    Hey! πŸ‘‹πŸ»

    First, thanks for your conf and blog posts regarding this architecture, they are really inspiring and I'm looking forward to having time and a project in which I can use this idea.

    Do you have any plans to include the web version with Kotlin/React in this repo? In your posts you talked about being able to use Compose in web too. Do you know if this happening and how's that going?

    Thanks!

    opened by iruizmar 1
  • Result from other view/state

    Result from other view/state

    Fantastic framework, loving it thanks!!

    Could you include a sample on how to get result from another view? E.g.: From the Country detail screen, I would have a button that navigates to a Friend Picker screen where I can select who of my friends were there. Now after selecting some friends, how do I get that information back into the Country Detail screen/state?

    many thanks again!

    opened by MvandeRuitenbeek 0
  • Bad Gateway trying to get compose runtime

    Bad Gateway trying to get compose runtime

    When trying to run the Android project I get the following error Could not HEAD 'https://kotlin.bintray.com/kotlinx/org/jetbrains/compose/runtime/runtime/1.0.1-rc2/runtime-1.0.1-rc2.pom'. Received status code 502 from server: Bad Gateway

    opened by m-nogas 1
  • Could not resolve ktor-client-js

    Could not resolve ktor-client-js

    When trying to build the Android app I get the following error:

    Could not resolve io.ktor:ktor-client-js:1.6.0.
    Required by:
        project :shared
    

    Android Studio Arctic Fox 2020.3.1, KMM Plugin 0.3.0

    opened by lukasz-kalnik-gcx 0
  • Error SockeTimeout when building `shared:runCommonizer` task

    Error SockeTimeout when building `shared:runCommonizer` task

    > Task :shared:runCommonizer
    Download https://github.com/yarnpkg/yarn/releases/download/v1.22.10/yarn-v1.22.10.tar.gz
    Failed building KotlinMPPGradleModel
    org.gradle.internal.operations.BuildOperationQueueFailure: There was a failure while
    

    Really unsure this is my internet connection or not, but it already 1h and failing twice.

    When trying to download the yarn, does the project have pre-req setup that I'm not aware of? :pray:

    opened by mochadwi 4
  • Navigation appears to be broken on iOS

    Navigation appears to be broken on iOS

    When setting up Navigation deeper then Level 2 on iOS, it stops working. As soon as a Level 3 screen is opened, the Navigation jumps back to Level 1. On Android, this does not happen, the Level 3 screen is displayed correctly.

    Steps to reproduce:

    1. Create a basic new screen in the shared library

    NEW file: TestScreenState.kt:

    data class TestScreenState (
        val isLoading: Boolean = false
    ): ScreenState
    

    NEW file: TestScreenInit.kt:

    data class TestScreenParams(val name: String) : ScreenParams
    
    fun Navigation.initTestScreen(params: TestScreenParams) = ScreenInitSettings (
        title = params.name,
        initState = { TestScreenState(isLoading = true)},
        callOnInit = {
            stateManager.updateScreen(TestScreenState::class) {
                it.copy(
                    isLoading = false
                )
            }
        }
    )
    

    ScreenEnum.kt:

    enum class Screen(
        val asString: String,
        val navigationLevel : Int = 1,
        val initSettings: Navigation.(ScreenIdentifier) -> ScreenInitSettings,
        val stackableInstances : Boolean = false,
    ) {
        CountriesList("countrieslist", 1, { initCountriesList(it.params()) }, true),
        CountryDetail("country", 2, { initCountryDetail(it.params()) }),
        TestScreen("testscreen", 3, {initTestScreen(it.params())}),
    }
    
    1. Add the screen to the iOS App, so that it can be navigated to from within CountryDetailScreen

    NEW file: TestScreen,swift:

    struct TestScreen: View {
        var testScreenState: TestScreenState
        
        var body: some View {
            VStack {
                if testScreenState.isLoading {
                    LoadingScreen()
                } else {
                    Text("Hello, World!")
                }
            }
        }
    }
    

    ScreenPicker.swift:

    case .countrydetail:
        CountryDetailScreen(
            countryDetailState: self.stateProvider.getToCast(screenIdentifier: sId) as! CountryDetailState,
            ontestScreenOpened: {name in self.navigate(.testscreen, TestScreenParams(name: name))}
        )
    case .testscreen:
        TestScreen(
            testScreenState: self.stateProvider.getToCast(screenIdentifier: sId) as! TestScreenState
        )
    

    CountryDetailScreen.swift:

    NavLink(linkFunction: {ontestScreenOpened("population")}) {
        DataElement(label: "total population", value: data.population)
    }
    
    1. Start App and navigate to the newly created screen
    opened by MstrCamp 6
Owner
null
ViewModel LiveData Sample - Sample of using ViewModel, LiveData and Data Binding

ViewModel_LiveData_Sample Sample Code for Lesson 8 using ViewModel, LiveData and

null 0 Mar 18, 2022
Plugin-shared-preferences - Pluto plugin to manage your Shared Preferences

Pluto Shared Preferences Plugin Pluto Shared Preferences is a Pluto plugin to in

Pluto 1 Feb 14, 2022
Android project setup files when developing apps from scratch. The codebase uses lates jetpack libraries and MVVM repository architecture for setting up high performance apps

Android architecture app Includes the following Android Respository architecture MVVM Jepack libraries Carousel view Kotlin Kotlin Flow and Livedata P

null 2 Mar 31, 2022
A minimal notes application in Jetpack Compose with MVVM architecture. Built with components like DataStore, Coroutines, ViewModel, LiveData, Room, Navigation-Compose, Coil, koin etc.

Paper - A Minimal Notes App A minimal notes application in Jetpack Compose with MVVM architecture. Built with components like DataStore, Coroutines, V

Akshay Sharma 139 Jan 2, 2023
GraphQL based Jetpack Compose and SwiftUI Kotlin Multiplatform sample

GraphQL based Jetpack Compose and SwiftUI Kotlin Multiplatform sample

John O'Reilly 151 Jan 3, 2023
Funstuff - Minimal Kotlin Multiplatform project with SwiftUI, Jetpack Compose, Compose for Wear OS, Compose for Desktop

PeopleInSpace Minimal Kotlin Multiplatform project with SwiftUI, Jetpack Compose

Shivam Dhuria 2 Feb 15, 2022
Shared ViewModel in Kotlin Multiplatform

multiplatform-viewmodel ?? Create shared ViewModel's for shared business logic using our ViewModel base class. Features Uses Jetpack ViewModel on Andr

Double Symmetry 16 Nov 8, 2022
Astha Nayak 4 Oct 10, 2022
Library to use Kotlin Coroutines from Swift code in KMP apps

KMP-NativeCoroutines A library to use Kotlin Coroutines from Swift code in KMP apps. Flows Kotlin Create an extension property to expose the Flow as a

Rick Clephas 508 Jan 3, 2023
Sample app that implements MVVM architecture using Kotlin, ViewModel, LiveData, and etc.

TheShard is a project to showcase different architectural approaches to developing Android apps. In its different branches you will find the same app (A movie Listing and detail page) implemented with small differences.

null 17 Aug 19, 2021
Kotlin Multiplatform lifecycle-aware business logic components (aka BLoCs) with routing functionality and pluggable UI (Jetpack Compose, SwiftUI, JS React, etc.), inspired by Badoos RIBs fork of the Uber RIBs framework

Decompose Please see the project website for documentation and APIs. Decompose is a Kotlin Multiplatform library for breaking down your code into life

Arkadii Ivanov 819 Dec 29, 2022
Kotlin Multiplatform Mobile + Mobile Declarative UI Framework (Jetpack Compose and SwiftUI)

Kotlin Multiplatform Mobile + Mobile Declarative UI Framework (Jetpack Compose and SwiftUI)

Kotchaphan Muangsan 3 Nov 15, 2022
MangaKu App Powered by Kotlin Multiplatform Mobile, Jetpack Compose, and SwiftUI

MangaKu ?? Introduction MangaKu App Powered by Kotlin Multiplatform Mobile, Jetpack Compose, and SwiftUI Module core: data and domain layer iosApp: io

Uwais Alqadri 132 Jan 8, 2023
Real life Kotlin Multiplatform project with an iOS application developed in Swift with SwiftUI, an Android application developed in Kotlin with Jetpack Compose and a backed in Kotlin hosted on AppEngine.

Conferences4Hall Real life Kotlin Multiplatform project with an iOS application developed in Swift with SwiftUI, an Android application developed in K

GΓ©rard Paligot 98 Dec 15, 2022
Sample application to demonstrate Multi-module Clean MVVM Architecture and usage of Android Hilt, Kotlin Flow, Navigation Graph, Unit tests etc.

MoneyHeist-Chars Sample application to demonstrate Multi-module Clean MVVM Architecture and usage of Android Hilt, Kotlin Flow, Navigation Graph, Room

Hisham 20 Nov 19, 2022
A beautiful Fashion Store like Android App Mock built on Jetpack Compose with compose navigation, hilt, dark theme support and google's app architecture found on uplabs Here

A beautiful Fashion Store like Android App Mock built on Jetpack Compose with compose navigation, hilt, dark theme support and google's app architecture found on uplabs Here

Puncz 87 Nov 30, 2022
ATH Sample is a sample Authentication and Authorization Application with Kotlin Language and MVVM architecture.

ATH Sample ATH Sample is a sample Authentication and Authorization Application with Kotlin Language and MVVM architecture. Overview ATH Sample is a sa

AbolfaZl RezaEi 4 Jun 8, 2021
FaceTimeClone app that implements Coroutines , mvvm architecture , clean architecture , navigation component , hilt , etc.... using kotlin language

This repository contains a FaceTimeClone app that implements Coroutines , mvvm architecture , clean architecture , navigation component , hilt , etc.... using kotlin language

null 17 Dec 13, 2022