Master Kotlin Compose Multiplatform: Build, Configure, and Package Desktop Apps
This article provides a comprehensive guide to using Kotlin, Jetpack Compose, and Multiplatform for desktop applications, covering project setup, shared code structure, platform-specific implementations, UI layout, resource handling, dependency configuration, and detailed packaging options for Windows, macOS, and Linux.
1. Introduction
Kotlin + Compose + Multiplatformcross‑platform solution is becoming mature by 2025. Google and JetBrains are deepening cooperation, unifying Jetpack Compose and Compose Multiplatform APIs, and Kotlin 2.1 will bring full‑platform backend optimizations.
Promising outlook – Google and JetBrains collaborate on API unification; enterprises such as McDonald’s and Netflix already reuse 80%+ business logic in production.
Multi‑platform coverage – Supports Android, iOS, desktop, Web and server code sharing via Compose Multiplatform; note some Jetpack libraries have compatibility limits. Compared with Flutter, KMP compiles to native binaries, preserving platform features.
Significant productivity boost – Declarative UI with Compose and coroutine‑based async reduces boilerplate; flexible sharing strategies allow sharing only business logic or extending to UI.
Performance equals native experience – Direct compilation to native code (iOS machine code, Android bytecode) avoids runtime overhead and enables native API calls such as SwiftUI/UIKit integration.
Complete desktop case study – The article walks through a full Kotlin + Compose + Multiplatform desktop project, covering new project creation, basic layout, custom title bar, skinning, ViewModel‑like usage, networking, file I/O, page navigation, file picker, music playback, video playback, KV storage and database usage.
2. Create New Project, Configure and Package
Use the Kotlin Multiplatform Wizard to generate a project template.
Project structure:
androidMain– Android‑specific code. commonMain – Shared code for all platforms. iosMain – iOS‑specific code. jvmMain – Windows/macOS/Linux specific code. wasmJsMain – Web specific code.
Platform‑specific implementations use the expect/actual mechanism:
// Definition
interface Platform {
val name: String
}
expect fun getPlatform(): Platform
// Usage
class Greeting {
private val platform = getPlatform()
fun greet(): String = "Hello, ${platform.name}!"
}Android implementation:
class AndroidPlatform : Platform {
override val name: String = "Android ${Build.VERSION.SDK_INT}"
}
actual fun getPlatform(): Platform = AndroidPlatform()JVM (desktop) implementation:
class JVMPlatform: Platform {
override val name: String = "Java ${System.getProperty("java.version")}"
}
actual fun getPlatform(): Platform = JVMPlatform()Dependency configuration examples: androidMain.dependencies { … } – Android‑specific libraries. commonMain.dependencies { … } – Libraries shared by all platforms. jvmMain.dependencies { … } – Desktop‑specific libraries.
Desktop packaging configuration (Compose Desktop):
compose.desktop {
application {
mainClass = "com.wx.music.MainKt"
nativeDistributions {
targetFormats(TargetFormat.Exe)
includeAllModules = true
jvmArgs += listOf("-Dfile.encoding=UTF-8", "--add-opens=java.base/java.lang=ALL-UNNAMED")
javaHome = "C:\\Users\\XXXX\\.jdks\\openjdk-21.0.1"
packageName = "WX音乐"
packageVersion = "1.0.0"
windows {
iconFile.set(project.file("src/desktopMain/composeResources/drawable/qwer.ico"))
shortcut = true
menu = true
}
}
buildTypes.release.proguard { isEnabled = false }
}
}Key packaging options: mainClass – Entry point for the desktop app. targetFormats – Choose .exe (Windows), .dmg (macOS) or .deb (Linux). includeAllModules = true – Bundle all dependencies. jvmArgs – Set UTF‑8 encoding and open java.lang for reflection. javaHome – Embed a specific JDK. iconFile – Set the .ico icon for Windows. shortcut and menu – Create desktop shortcuts and menu entries.
ProGuard can be disabled for release builds.
Packaging tasks such as package, packageDeb, packageDistributionForCurrentOS, packageDmg and packageExe generate installers for the respective operating systems.
3. Basic Layout, Text, Icons and Images
The UI code for Android Jetpack Compose works identically on desktop. Resources are placed under drawable (SVG XML) and images (png, jpg, webp). Example of using a local SVG icon:
Icon(
modifier = Modifier
.padding(0.dp, 0.dp, 80.dp, 0.dp)
.clickable { minRequest.invoke() }
.size(40.dp)
.padding(0.dp, 0.dp, 0.dp, 15.dp)
.align(Alignment.TopEnd),
painter = painterResource("drawable/baseline_minimize_24.xml"),
contentDescription = "Close",
tint = MaterialTheme.colorScheme.onPrimary
)Network images are loaded with Coil, which supports Android, iOS, JVM, JavaScript and WASM:
implementation("io.coil-kt.coil3:coil-compose:3.0.3")
implementation("io.coil-kt.coil3:coil-network-okhttp:3.0.3") AsyncImage(
model = item.pic,
contentDescription = "Network Image",
modifier = Modifier.fillMaxSize().clip(RoundedCornerShape(10)),
contentScale = ContentScale.Crop
)4. Summary
The article presented a complete Kotlin + Compose + Multiplatform desktop case, including project creation, configuration, packaging, basic UI layout, resource handling, and outlined future topics such as custom title bars, skinning, ViewModel‑like patterns, networking, file I/O, navigation, file picker, music and video playback, KV storage and database usage.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
