Compose multiplatform
Skill almasumdev/awesome-kotlin-multiplatform-agent-skills/.github/skills/ui/compose-multiplatform
Sharing UI with Compose Multiplatform 1.7+ across Android, iOS, Desktop (JVM), and Web (wasmJs). Covers module layout, entry points per platform, lifecycle, and when UI-per-platform is still better. Use when building shared screens.From its SKILL.md
npx -y skills add almasumdev/awesome-kotlin-multiplatform-agent-skills --skill compose-multiplatformAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
4.8 KB, ~1.0k tokens by cl100k_base, as published. Nobody here has run it
Compose Multiplatform
Instructions
Compose Multiplatform (CMP) lets you write one @Composable tree that renders on Android (via Jetpack Compose), iOS (via Skia/Metal), Desktop, and Web. It is stable for Android/Desktop, stable for iOS (1.7+), beta for wasmJs.
1. Module & plugin setup
// shared/build.gradle.kts
plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.androidLibrary)
alias(libs.plugins.composeMultiplatform)
alias(libs.plugins.composeCompiler) // Kotlin 2.0+ compose compiler plugin
}
kotlin {
androidTarget()
jvm("desktop")
listOf(iosArm64(), iosSimulatorArm64(), iosX64()).forEach {
it.binaries.framework { baseName = "Shared"; isStatic = true }
}
sourceSets {
commonMain.dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
implementation(compose.components.resources)
implementation(compose.components.uiToolingPreview)
}
}
}
2. A shared screen
// commonMain
@Composable
fun App(viewModel: CounterViewModel) {
val state by viewModel.state.collectAsState()
MaterialTheme {
Column(
modifier = Modifier.fillMaxSize().padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
Text("Count: ${state.count}", style = MaterialTheme.typography.headlineMedium)
Spacer(Modifier.height(16.dp))
Button(onClick = viewModel::increment) { Text("Increment") }
}
}
}
3. Android entry point
// androidApp
class MainActivity : ComponentActivity() {
private val viewModel: CounterViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent { App(viewModel) }
}
}
4. iOS entry point
// iosMain — expose to Swift
fun mainViewController(viewModel: CounterViewModel): UIViewController =
ComposeUIViewController { App(viewModel) }
// iosApp (SwiftUI)
import SwiftUI
import Shared
struct ContentView: View {
let viewModel: CounterViewModel
var body: some View {
ComposeView(viewModel: viewModel).ignoresSafeArea(.keyboard)
}
}
struct ComposeView: UIViewControllerRepresentable {
let viewModel: CounterViewModel
func makeUIViewController(context: Context) -> UIViewController {
Shared_iosKt.mainViewController(viewModel: viewModel)
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}
5. Desktop entry point
// desktopApp
fun main() = application {
val viewModel = remember { CounterViewModel() }
Window(onCloseRequest = ::exitApplication, title = "My App") { App(viewModel) }
}
6. Lifecycle & view-models
Use the multiplatform androidx.lifecycle:lifecycle-viewmodel-compose (stable for KMP since 2.8). ViewModel and viewModelScope now exist in commonMain:
class CounterViewModel : ViewModel() {
private val _state = MutableStateFlow(CounterState())
val state: StateFlow<CounterState> = _state.asStateFlow()
fun increment() = viewModelScope.launch {
_state.update { it.copy(count = it.count + 1) }
}
}
7. When UI-per-platform is better
Share UI when the screens should look and behave identically and the feature set is within Compose's reach. Keep UI per platform when:
- You need fully native widgets (SwiftUI
Listwith swipe actions, AndroidAppWidget, system share sheets). - Accessibility / haptics / gesture nuances must match platform conventions exactly.
- Integrating deeply with platform navigation (SwiftUI
NavigationStackbacked by UIKit transitions).
In those cases keep presenters (StateFlow-emitting view-models) in commonMain and write native UI per target.
Checklist
-
compose.runtime+compose.material3come from thecomposeMultiplatformplugin, not AndroidX directly. - Kotlin 2.0+
composeCompilerplugin applied (replaces the legacy compiler config). -
MaterialTheme(or a project-wide theme wrapper) wraps every entry-point composable. - View-models in
commonMainexposeStateFlow; they never touchContext/UIViewControllerdirectly. - iOS uses
ComposeUIViewController { }bridge; the Swift side does not re-declare theming. - Desktop window provides a sensible min/default size.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.