[ Documentation ]
Android overview

Android overview

Peach runs Android apps written in Kotlin and Jetpack Compose in the browser. Point peach kotlin at your app module and Peach reads its manifest, Gradle files and Kotlin sources unchanged, compiles them on your machine, and cold-starts the launcher activity on a simulated Pixel the way Android starts it.

terminal
peach kotlin ./app

Kotlin support is in beta. It runs Compose apps whose dependencies sit in the Compose closure Peach pins, and it rejects anything outside that closure with the file and line, so you know right away whether your app fits.

What runs

  • +
    Your app module as written: AndroidManifest.xml, build.gradle.kts or build.gradle, and the Kotlin sources under src/main. No Gradle build runs; Peach reads literal values from your Gradle files.
  • +
    Activities: the launcher activity or alias resolves from the manifest’s MAIN/LAUNCHER intent filter, or you open another exported activity with --activity.
  • +
    Compose: Compose UI, foundation and Material 3 at Peach’s pinned versions, plus navigation, activity-compose, lifecycle and saved state.
  • +
    The Android app model: your Application, ComponentActivity and its lifecycle callbacks, setContent, saved instance state, ViewModels, rememberSaveable, and configuration changes.
  • +
    Resources: themes from res/values and res/values-night, colors, and vector and bitmap drawables selected by density and API level.

How it renders

Your Kotlin compiles to WebAssembly with the pinned Kotlin compiler and runs in Peach’s app worker. Compose draws with Skia, and Peach replays those drawings through the same GPU Skia renderer that paints every other app in Peach. There is no second renderer and no emulator. The Android status bar, navigation bar, keyboard and system chrome come from Peach’s Android device surface.

See How Peach works for the worker model behind that.

Android behavior Peach follows

Peach follows what Android does, measured against real Android builds of the same project:

  • +
    Cold start runs your Application and launcher activity in the order Android’s activity thread runs them, then attaches the window.
  • +
    Lifecycle: going home pauses and stops the activity and saves its instance state. Coming back restarts it (onRestart, onStart, onResume).
  • +
    Dark theme is the configuration’s night mode. Changing it relaunches the activity from its saved state, keeping its ViewModels and rememberSaveable values, unless the activity declares uiMode in configChanges, in which case it receives onConfigurationChanged. isSystemInDarkTheme() follows the device.
  • +
    Edge to edge: apps targeting SDK 35 and above draw edge to edge, and enableEdgeToEdge() behaves as androidx.activity does. Compose receives system bar, display cutout, gesture and tappable element insets, and the keyboard’s animated IME inset.
  • +
    Back: Back dispatches by window, priority and registration order. Predictive Back is on when your manifest enables it or your target SDK is above 35, and an unhandled Back sends the task behind home.

Limits today

  • +
    Java sources are not supported. Your module’s sources must be Kotlin.
  • +
    Gradle values must be literals, and every dependency must be in Peach’s pinned Compose closure at the pinned version. Only the Android application, Kotlin Android and Compose compiler plugins are accepted.
  • +
    Content providers, android:process, appComponentFactory and manifest placeholders are rejected by name.
  • +
    Colors resolve from values and values-night only. Other resource qualifiers, gradient drawables and nine-patches are refused with their location. Dynamic (wallpaper) color is refused by name.
  • +
    An edit restarts the app with fresh state, as reinstalling a rebuilt app does. State is not carried across edits the way it is for Swift.
  • +
    Changing the device language after launch, keyboard input routing, and Compose semantics in Peach’s inspection tools are not graded against Android yet.
  • +
    Peach’s Roboto font differs slightly from the system Roboto on a device, so glyphs do not match a device pixel for pixel.

Next steps