Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin Multiplatform at Stable and Beyond (Kotl...

Kotlin Multiplatform at Stable and Beyond (Kotlin Vienna, October 2024)

Kotlin Multiplatform became stable last year, making it ready for production use for anyone looking to share code between platforms. In this talk, we’ll take a look at what that announcement means for Kotlin Multiplatform, and how the technology is evolving now, beyond the stable release.

You’ll hear about UI sharing with Compose Multiplatform, the latest of Kotlin multiplatform tooling, the experimental Amper project, and more!

More details: https://zsmb.co/talks/kmp-at-stable-and-beyond/

Márton Braun

October 01, 2024
Tweet

More Decks by Márton Braun

Other Decks in Programming

Transcript

  1. .kt .kt .kt Android Desktop iOS Common class Person(val name:

    String, var age: Int) fun greet(person: Person) { println("Hello, ${person.name}") }
  2. .kt .kt .kt Android Desktop iOS Common fun List<Person>.duplicates(): Map<String,

    Int> { return map { it.name.substringBefore(" ") } .groupingBy { it } .eachCount() .filter { (name, count) -> count > 1 } }
  3. Android Desktop iOS Common fun getPlatform(): String fun getPlatform(): String

    = "Java ${System.getProperty("java.version")}" expect actual actual actual
  4. 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
  5. 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
  6. 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
  7. .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<String>() }
  8. Compiler support Language features Library APIs Build tooling IDE support

    Strict compatibility guarantees kotl.in/kmp-stability
  9. 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) } } }
  10. 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) } } }
  11. 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
  12. 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
  13. 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 }
  14. 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) } } }
  15. 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
  16. @Composable fun SquaresGalleryView( images: List<PictureData>, 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 ) } } }
  17. @Composable fun SquaresGalleryView( images: List<PictureData>, 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 ) } } }
  18. Desktop logic Android logic iOS logic Shared logic Shared UI

    Compose Multiplatform Swing Jetpack Compose SwiftUI
  19. Resources • Multi-module projects and library publication • Configuration options

    for generated file • Plural strings • Resource directories in multiple source sets
  20. 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
  21. 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
  22. 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() } ) } } )
  23. 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() } ) } } )
  24. Navigation org.jetbrains.androidx.navigation:navigation-compose val controller = rememberNavController() NavHost(navController = controller, startDestination

    = ListDestination) { composable<ListDestination> { ListScreen( navToDetails = { objectId -> controller.navigate(DetailDestination(objectId) } ) } composable<DetailDestination> { backStack -> DetailScreen( objectId = backStack.toRoute<DetailDestination>().objectId, navBack = { controller.popBackStack() } ) } } )