Slide 1

Slide 1 text

Kotlin Multiplatform at Stable and Beyond Márton Braun Developer Advocate

Slide 2

Slide 2 text

iOS Android Desktop Web Server

Slide 3

Slide 3 text

iOS Android Desktop Web Server

Slide 4

Slide 4 text

iOS Android Desktop +

Slide 5

Slide 5 text

.kt .kt .kt .kt Android Desktop iOS Common

Slide 6

Slide 6 text

.kt .kt .kt .kt Android Desktop iOS Common

Slide 7

Slide 7 text

.kt .kt .kt Android Desktop iOS Common class Person(val name: String, var age: Int) fun greet(person: Person) { println("Hello, ${person.name}") }

Slide 8

Slide 8 text

.kt .kt .kt Android Desktop iOS Common fun List.duplicates(): Map { return map { it.name.substringBefore(" ") } .groupingBy { it } .eachCount() .filter { (name, count) -> count > 1 } }

Slide 9

Slide 9 text

Android Desktop iOS actual Common expect actual actual

Slide 10

Slide 10 text

Android Desktop iOS Common expect actual actual actual

Slide 11

Slide 11 text

Android Desktop iOS Common fun getPlatform(): String expect actual actual actual

Slide 12

Slide 12 text

Android Desktop iOS Common fun getPlatform(): String fun getPlatform(): String = "Java ${System.getProperty("java.version")}" expect actual actual actual

Slide 13

Slide 13 text

Android iOS fun getPlatform(): String = "Android ${Build.VERSION.SDK_INT}" actual actual Common fun getPlatform(): String expect Desktop fun getPlatform(): String = "Java ${System.getProperty("java.version")}" actual

Slide 14

Slide 14 text

Android iOS fun getPlatform(): String = "iOS ${UIDevice.currentDevice.systemVersion}" fun getPlatform(): String = "Android ${Build.VERSION.SDK_INT}" actual actual Common fun getPlatform(): String expect Desktop fun getPlatform(): String = "Java ${System.getProperty("java.version")}" actual

Slide 15

Slide 15 text

Android Desktop iOS Common fun getPlatform(): String fun getPlatform(): String = "Java ${System.getProperty("java.version")}" fun getPlatform(): String = "iOS ${UIDevice.currentDevice.systemVersion}" fun getPlatform(): String = "Android ${Build.VERSION.SDK_INT}" expect actual actual actual

Slide 16

Slide 16 text

Multiplatform libraries

Slide 17

Slide 17 text

github.com/terrakok/kmp-awesome

Slide 18

Slide 18 text

.kt .kt .kt Android Desktop iOS Common import io.ktor.client.* suspend fun loadHtml(): String { val client = HttpClient() val response = client.get("https://kotlinlang.org") return response.body() }

Slide 19

Slide 19 text

Shared logic

Slide 20

Slide 20 text

Shared logic Swing Desktop logic Jetpack Compose Android logic SwiftUI iOS logic

Slide 21

Slide 21 text

Shared logic Swing Desktop logic Jetpack Compose Android logic SwiftUI iOS logic

Slide 22

Slide 22 text

Shared logic Swing Desktop logic Jetpack Compose Android logic SwiftUI iOS logic

Slide 23

Slide 23 text

2019 2020 2021 2022 2023 2024 2025 Experimental ➟

Slide 24

Slide 24 text

Alpha 2019 2020 2021 2022 2023 2024 2025

Slide 25

Slide 25 text

Beta 2019 2020 2021 2022 2023 2024 2025

Slide 26

Slide 26 text

Stable 2019 2020 2021 2022 2023 2024 2025

Slide 27

Slide 27 text

Stable 2019 2020 2021 2022 2023 2024 2025

Slide 28

Slide 28 text

Compiler support Language features Library APIs Build tooling IDE support Strict compatibility guarantees kotl.in/kmp-stability

Slide 29

Slide 29 text

Configuring targets kotlin { androidTarget() iosArm64() iosSimulatorArm64() sourceSets { val commonMain by getting val iosMain by creating { dependsOn(commonMain) } val iosArm64Main by creating { dependsOn(iosMain) } val iosSimulatorArm64Main by creating { dependsOn(iosMain) } } }

Slide 30

Slide 30 text

Configuring targets kotlin { androidTarget() iosArm64() iosSimulatorArm64() sourceSets { val commonMain by getting val iosMain by creating { dependsOn(commonMain) } val iosArm64Main by creating { dependsOn(iosMain) } val iosSimulatorArm64Main by creating { dependsOn(iosMain) } } }

Slide 31

Slide 31 text

Configuring targets kotlin { androidTarget() iosArm64() iosSimulatorArm64() }

Slide 32

Slide 32 text

common jvm android native js androidNative apple mingw linux iosArm64 iosSimulatorArm64 mingwX64 android_arm64 ... ios macos tvos watchos Configuring targets kotlin { androidTarget() iosArm64() iosSimulatorArm64() } iosArm64 iosX64 iosSimulatorArm64 iosArm64 iosSimulatorArm64 iosArm64 iosSimulatorArm64 iosArm64 iosSimulatorArm64

Slide 33

Slide 33 text

common jvm android native js androidNative apple mingw linux iosArm64 iosSimulatorArm64 mingwX64 android_arm64 ... ios macos tvos watchos Configuring targets kotlin { androidTarget() iosArm64() iosSimulatorArm64() } iosX64 iosArm64 iosSimulatorArm64 iosArm64 iosSimulatorArm64 iosArm64 iosSimulatorArm64 iosArm64 iosSimulatorArm64

Slide 34

Slide 34 text

common jvm android native js androidNative apple mingw linux iosArm64 iosSimulatorArm64 mingwX64 android_arm64 ... ios macos tvos watchos Configuring targets kotlin { androidTarget() iosArm64() iosSimulatorArm64() iosX64 iosArm64 iosSimulatorArm64 iosArm64 iosSimulatorArm64 iosArm64 iosSimulatorArm64 iosArm64 iosSimulatorArm64 }

Slide 35

Slide 35 text

Configuring targets kotlin { androidTarget() iosArm64() iosSimulatorArm64() sourceSets { } } m m o c

Slide 36

Slide 36 text

Configuring targets kotlin { androidTarget() iosArm64() iosSimulatorArm64() sourceSets { commonMain } }

Slide 37

Slide 37 text

Configuring targets kotlin { androidTarget() iosArm64() iosSimulatorArm64() sourceSets { commonMain.dependencies { implementation(libs.ktor.client.core) } androidMain.dependencies { implementation(libs.ktor.client.okhttp) } iosMain.dependencies { implementation(libs.ktor.client.darwin) } } }

Slide 38

Slide 38 text

Gradle configuration cache support Build and runtime performance 📈 Incremental compilation of klib artifacts 🧪 New custom memory allocator in Kotlin/Native Kotlin/Native compiler cache management

Slide 39

Slide 39 text

kotl.in/kmp-portal

Slide 40

Slide 40 text

Kotlin-Swift interopedia kotl.in/interopedia forked from hhru/kotlin-swift-interopedia

Slide 41

Slide 41 text

Currently via Objective-C

Slide 42

Slide 42 text

Work in progress via Objective-C

Slide 43

Slide 43 text

Work in progress github.com/Kotlin/swift-export-sample

Slide 44

Slide 44 text

Demo kmp.jetbrains.com

Slide 45

Slide 45 text

Public Preview

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

No content

Slide 50

Slide 50 text

Demo

Slide 51

Slide 51 text

Shared logic Swing Desktop logic Jetpack Compose Android logic SwiftUI iOS logic

Slide 52

Slide 52 text

Shared logic Swing Desktop logic Jetpack Compose Android logic SwiftUI iOS logic

Slide 53

Slide 53 text

jb.gg/compose Compose Multiplatform

Slide 54

Slide 54 text

Compose Multiplatform jb.gg/compose

Slide 55

Slide 55 text

@Composable fun SquaresGalleryView( images: List, selectedImage: PictureData, onSelect: (PictureData) -> Unit, ) { LazyVerticalGrid( modifier = Modifier.padding(top = 4.dp), columns = GridCells.Adaptive(minSize = 130.dp), verticalArrangement = Arrangement.spacedBy(1.dp), horizontalArrangement = Arrangement.spacedBy(1.dp) ) { itemsIndexed(images) { _, picture -> SquareThumbnail( picture = picture, onClick = { onSelect(picture) }, isHighlighted = selectedImage === picture ) } } }

Slide 56

Slide 56 text

@Composable fun SquaresGalleryView( images: List, selectedImage: PictureData, onSelect: (PictureData) -> Unit, ) { LazyVerticalGrid( modifier = Modifier.padding(top = 4.dp), columns = GridCells.Adaptive(minSize = 130.dp), verticalArrangement = Arrangement.spacedBy(1.dp), horizontalArrangement = Arrangement.spacedBy(1.dp) ) { itemsIndexed(images) { _, picture -> SquareThumbnail( picture = picture, onClick = { onSelect(picture) }, isHighlighted = selectedImage === picture ) } } }

Slide 57

Slide 57 text

Swing Desktop logic Jetpack Compose Android logic SwiftUI iOS logic Shared logic

Slide 58

Slide 58 text

Desktop logic Android logic iOS logic Shared logic Shared UI Compose Multiplatform

Slide 59

Slide 59 text

Desktop logic Android logic iOS logic Shared logic Shared UI Compose Multiplatform Swing Jetpack Compose SwiftUI

Slide 60

Slide 60 text

Latest developments Resources 1.6.0+ Lifecycle Navigation 2.8.0 2.8.0-alpha09 ViewModel 2.8.0

Slide 61

Slide 61 text

Resources org.jetbrains.compose.components:components-resources composeResources

Slide 62

Slide 62 text

Resources org.jetbrains.compose.components:components-resources drawable files font values composeResources

Slide 63

Slide 63 text

Resources org.jetbrains.compose.components:components-resources drawable files font values -de -en-rUS -mdpi -xxhdpi -light -dark composeResources

Slide 64

Slide 64 text

Demo

Slide 65

Slide 65 text

Resources • Multi-module projects and library publication • Configuration options for generated file • Plural strings • Resource directories in multiple source sets

Slide 66

Slide 66 text

Lifecycle org.jetbrains.androidx.lifecycle:lifecycle-common

Slide 67

Slide 67 text

Lifecycle on Desktop org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose Swing listener callbacks Lifecycle event Lifecycle state change windowLostFocus ON_PAUSE RESUMED → STARTED windowGainedFocus ON_RESUME STARTED → RESUMED windowIconified ON_STOP STARTED → CREATED windowDeiconified ON_START CREATED → STARTED dispose ON_DESTROY CREATED → DESTROYED

Slide 68

Slide 68 text

Demo

Slide 69

Slide 69 text

ViewModel org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose package androidx.lifecycle public abstract class ViewModel { protected open fun onCleared() public fun addCloseable(key: String, closeable: AutoCloseable) public open fun addCloseable(closeable: AutoCloseable) } public val ViewModel.viewModelScope: CoroutineScope

Slide 70

Slide 70 text

ViewModelStoreOwner implementations Who owns the ViewModel?

Slide 71

Slide 71 text

ViewModelStoreOwner implementations 🗄 ComponentActivity ComposeView ComponentActivity Who owns the ViewModel?

Slide 72

Slide 72 text

ViewModelStoreOwner implementations 🗄 ComponentActivity ComposeView ComponentActivity Who owns the ViewModel?

Slide 73

Slide 73 text

ViewModelStoreOwner implementations SwiftUI 🗄 ComposeUIVC ComponentActivity ComposeUIViewController ComposeWindow CanvasBasedWindow Who owns the ViewModel?

Slide 74

Slide 74 text

ViewModelStoreOwner implementations SwiftUI 🗄 ComposeUIVC ComponentActivity ComposeUIViewController ComposeWindow CanvasBasedWindow Who owns the ViewModel?

Slide 75

Slide 75 text

ViewModelStoreOwner implementations NavBackStackEntry🗄 NavBackStackEntry🗄 NavBackStackEntry ComponentActivity ComposeUIViewController ComposeWindow CanvasBasedWindow Who owns the ViewModel? 🗄 ComposeUIVC

Slide 76

Slide 76 text

ViewModelStoreOwner implementations NavBackStackEntry🗄 NavBackStackEntry🗄 NavBackStackEntry ComponentActivity ComposeUIViewController ComposeWindow CanvasBasedWindow Who owns the ViewModel? 🗄 ComposeUIVC

Slide 77

Slide 77 text

ViewModelStoreOwner implementations YourCustomOwner 🗄 Provide your own! NavBackStackEntry ComponentActivity ComposeUIViewController ComposeWindow CanvasBasedWindow Who owns the ViewModel?

Slide 78

Slide 78 text

Navigation org.jetbrains.androidx.navigation:navigation-compose val controller = rememberNavController() NavHost(navController = controller, startDestination = "list") { composable("list") { ListScreen( navToDetails = { objectId -> controller.navigate("details/$objectId" } ) } composable("details/{objectId}") { backStack -> DetailScreen( objectId = backStack.arguments?.getString("objectId"), navBack = { controller.popBackStack() } ) } } )

Slide 79

Slide 79 text

Navigation org.jetbrains.androidx.navigation:navigation-compose val controller = rememberNavController() NavHost(navController = controller, startDestination = "list") { composable("list") { ListScreen( navToDetails = { objectId -> controller.navigate("details/$objectId" } ) } composable("details/{objectId}") { backStack -> DetailScreen( objectId = backStack.arguments?.getString("objectId"), navBack = { controller.popBackStack() } ) } } )

Slide 80

Slide 80 text

Navigation org.jetbrains.androidx.navigation:navigation-compose val controller = rememberNavController() NavHost(navController = controller, startDestination = ListDestination) { composable { ListScreen( navToDetails = { objectId -> controller.navigate(DetailDestination(objectId) } ) } composable { backStack -> DetailScreen( objectId = backStack.toRoute().objectId, navBack = { controller.popBackStack() } ) } } )

Slide 81

Slide 81 text

Demo

Slide 82

Slide 82 text

Amper Experimental jb.gg/amper

Slide 83

Slide 83 text

Demo

Slide 84

Slide 84 text

jb.gg/amper jb.gg/amper-slack jb.gg/amper-issues jb.gg/amper-blog

Slide 85

Slide 85 text

Kotlin Multiplatform jb.gg/kmp Compose Multiplatform jb.gg/compose jb.gg/compose-resources jb.gg/compose-navigation jb.gg/compose-lifecycle Fleet jb.gg/fleet Amper jb.gg/amper Kotlin Multiplatform at Stable and Beyond zsmb.co/talks Márton Braun @[email protected]