---
name: android-compose-multiplatform
description: "One Compose codebase for Android, iOS, and Desktop — shared UI without React Native compromises. Scaffolds Compose Multiplatform projects: shared composables, expect/actual platform code, Gradle config, and the iOS Xcode wrapper."
license: MIT
---

# Compose Multiplatform Builder

Scaffolds a working JetBrains Compose Multiplatform project that shares Kotlin UI code across Android, iOS, and Desktop (JVM) from a single `commonMain` source set. It's aimed at Kotlin and Android developers who want one Compose codebase across platforms instead of maintaining parallel SwiftUI/XML trees, and who'd rather not hand-wire the iOS Xcode integration themselves.

## When to use it

- Starting a greenfield app that should ship to Android and iOS with shared screens.
- You already have Compose UI on Android and want to lift it into `commonMain` for reuse.
- You need a Desktop build (JVM window) for previews, demos, or an internal tool alongside mobile.
- You want the iOS half wired correctly the first time: framework export plus an Xcode project that hosts the shared UI in a `UIViewController`.

## What it does

The skill generates a standard KMP module layout: `composeApp/src/commonMain` for shared `@Composable` code, plus `androidMain`, `iosMain`, and `desktopMain` (jvmMain) for platform specifics. It wires the `kotlin("multiplatform")` and `org.jetbrains.compose` Gradle plugins, declares the `compose.runtime`, `compose.foundation`, `compose.material3`, and `compose.ui` dependencies in the common source set, and adds the `kotlin.cocoapods` or framework-export config so iOS gets a `ComposeApp` framework.

Platform-specific behavior uses the `expect`/`actual` pattern — e.g. an `expect fun platformName()` declared in common with `actual` implementations per target. Entry points are handled per platform: an `Activity` calling `setContent { App() }` on Android, `ComposeUIViewController { App() }` on iOS, and `application { Window { App() } }` on Desktop. The iOS Xcode wrapper project links the exported framework and presents that controller.

## Usage

```bash
curl -fsSL --create-dirs -o ~/.claude/skills/android-compose-multiplatform/SKILL.md https://claudeskil.com/skills/android-compose-multiplatform/SKILL.md

# then, in your project:
"Scaffold a Compose Multiplatform app named TripLog targeting Android, iOS, and Desktop"
```

```kotlin
// commonMain — shared across all three targets
@Composable
fun App() {
    MaterialTheme {
        var count by remember { mutableStateOf(0) }
        Button(onClick = { count++ }) {
            Text("Running on ${platformName()}: $count")
        }
    }
}

// commonMain
expect fun platformName(): String
// iosMain → actual fun platformName() = UIDevice.currentDevice.systemName()
```

## Tips & gotchas

- Run iOS via the generated Xcode project (or the KMP run config), not `./gradlew`; Gradle builds the framework, Xcode builds the app.
- Keep Android-only APIs (`Context`, resources) out of `commonMain` — push them behind `expect`/`actual` or they won't compile for iOS.
- Resources go through `compose.components.resources` (`Res.drawable.*`), not Android `R`.
- A consistent Kotlin and Compose Multiplatform plugin version pairing matters; mismatches surface as cryptic Gradle metadata errors.

## FAQ

**Does this use Swift for the iOS UI?** No — the UI is Compose. Swift only appears in the thin Xcode wrapper hosting the Compose view controller, so you can still add native screens if needed.

**Can I drop into SwiftUI for a specific screen?** Yes. `ComposeUIViewController` is a normal `UIViewController`, so you can present it from SwiftUI/UIKit or mix native screens around it.

**Is the Desktop target required?** No. It's included for fast previews and runs on the JVM, but you can target only Android and iOS.
