[ Documentation ]
Run a Compose app

Run a Compose app

This guide takes a Kotlin and Jetpack Compose app from a folder on your disk to a running Pixel in Peach, walks it through Android’s lifecycle, and ends with a screenshot and a recording you can send. Kotlin support is in beta; see the Android overview for what runs today.

1. Install Peach and Java

If you have not installed Peach yet, follow the Quick start.

peach kotlin compiles with the Kotlin compiler, which runs on Java 17 or newer. Check that one is available:

terminal
java -version

If that fails, install a JDK and set JAVA_HOME or put java on your PATH. You do not need Android Studio, the Android SDK, Gradle or an emulator.

2. Have a Compose project

Use your own app, or create this one. It has the layout Android Studio generates: a project root with settings.gradle.kts, and an app module.

Counter/
settings.gradle.kts
build.gradle.kts
app/
build.gradle.kts
src/main/AndroidManifest.xml
src/main/java/com/example/counter/MainActivity.kt

settings.gradle.kts:

pluginManagement { repositories { google(); mavenCentral(); gradlePluginPortal() } }
dependencyResolutionManagement { repositories { google(); mavenCentral() } }
rootProject.name = "Counter"
include(":app")

build.gradle.kts:

plugins {
id("com.android.application") version "9.2.1" apply false
id("org.jetbrains.kotlin.android") version "2.2.0" apply false
id("org.jetbrains.kotlin.plugin.compose") version "2.2.0" apply false
}

app/build.gradle.kts:

plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("org.jetbrains.kotlin.plugin.compose")
}
android {
namespace = "com.example.counter"
compileSdk = 37
defaultConfig {
applicationId = "com.example.counter"
minSdk = 24
targetSdk = 37
versionCode = 1
versionName = "1"
}
buildFeatures { compose = true }
}
dependencies {
implementation("androidx.activity:activity-compose:1.13.0")
implementation("androidx.compose.ui:ui:1.13.0-alpha02")
implementation("androidx.compose.foundation:foundation:1.13.0-alpha02")
implementation("androidx.compose.material3:material3:1.5.0-alpha27")
}

app/src/main/AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:label="Counter" android:theme="@android:style/Theme.Material.Light.NoActionBar">
<activity android:name=".MainActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

app/src/main/java/com/example/counter/MainActivity.kt:

package com.example.counter
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
var count by rememberSaveable { mutableIntStateOf(0) }
Column(
Modifier.fillMaxSize().safeDrawingPadding().padding(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
Text("Hello from Compose")
Button(onClick = { count += 1 }) { Text("Count: $count") }
}
}
}
}

Every dependency is written as a literal coordinate at the version Peach pins. If your own app uses a Compose BOM or version catalog aliases in dependencies, write the coordinates out for Peach; see Running Compose apps.

3. Run it

Pass the app module, not the project root:

terminal
peach kotlin ./Counter/app

The first run downloads Peach’s pinned Kotlin compiler and Compose libraries once and caches them. Then Peach compiles, prints the activity it launches, and opens the app on a Pixel 10:

Kotlin app: com.example.counter.MainActivity in …/Counter/app
Kotlin preview host: http://127.0.0.1:…
Kotlin artifact: …

If Peach refuses the project, the message names the file and line: a Gradle value that is not a literal, a plugin or dependency outside its closure, or a manifest feature it does not support yet. Fix that line and run again.

Tap Count a few times.

4. Exercise the lifecycle

In a second terminal, switch the device to dark appearance:

terminal
peach shell appearance dark

The activity relaunches from its saved state, as Android relaunches it for a night mode change. The count survives because it is held in rememberSaveable. Switch back with peach shell appearance light.

Send the app home:

terminal
peach shell home

Going home pauses and stops the activity, then saves its instance state, in Android’s order. When the app returns to the foreground, the activity restarts with onRestart, onStart and onResume.

5. Edit it

Leave peach kotlin running, change "Hello from Compose" in MainActivity.kt, and save. Peach recompiles, prints a new Kotlin artifact, and restarts the app with the new code, as installing a rebuilt app does. The count starts again from zero, because a new process starts fresh.

If the build fails, the error prints in the terminal and the running app stays as it was until your next good save.

6. Try another device

Stop with Ctrl+C, then pick another Android device:

terminal
peach kotlin ./Counter/app --device galaxy-s24

7. Capture and share

With the app running, in a second terminal:

terminal
peach screenshot --output counter.png
peach record --duration 8 --output counter.mp4

Send the PNG or MP4 to anyone; they need nothing installed to view them. For a hosted preview link, and how its visibility works, see Sharing. Hosted live links have not been verified with Kotlin apps yet, so open a link yourself before you send it, and send the recording when it matters.

8. Stop

Press Ctrl+C in the peach kotlin terminal. Peach closes the preview, the host and the file watcher it started.

Next steps

  • +
    Running Compose apps covers activities, lifecycle, saved state, insets, Back and every flag.
  • +
    Testing runs flows against your running app.
  • +
    Device state sets the device conditions your app reads.