Get Started With Compose Multiplatform To Build Desktop And Mobile Apps


Get started with Compose Multiplatform by JetBrains
Cross platform desktop and mobile development using the Kotlin programming language and the Compose Multiplatform technology by JetBrains.

Introduction

Compose Multiplatform is a UI framework made by Jetbrains to simplify and accelerate desktop and mobile application development using Kotlin with a more declarative API (less imperative). It targets the JVM and thus can be used to build cross platform GUI apps. It also supports other platforms such as web.

It's based on Kotlin Multiplatform that enables cross-platform development and the Jetpack Compose declarative UI Toolkit made by Google for Android. Combining the two technologies make it possible to share, partially or entirely, UI implementation for your applications on Android, Windows, iOS, macOS and Linux. More details about the compatibility and the differences with Jetpack Compose available here.

Using Kotlin to design user interfaces promotes less bugs, better tooling support and more concise and robust code. This is achieved using a declarative UI model based on composable functions, which take in parameters to describe the UI logic without returning anything and must be free of side-effects. A more complete conceptual model is presented in this Thinking in Compose documentation page.

Getting started

JDK 11 or later is required. You can either use the JDK provided by the IDE, IntelliJ IDEA Community Edition or Ultimate Edition 20.2 or later, or follow this tutorial if you need to get started with Java, JDK and IntelliJ IDEA.

  1. Use the Kotlin Multiplatform Wizard to create and download your project starter. In this tutorial we will be using desktop and Android, but you can select just desktop at first
  2. Extract and move the folder to your workspace
  3. Open IntelliJ IDEA and from the files menu, create a project from existing sources using the extracted folder
  4. Choose Gradle as the build system
  5. To start the project, either open the main.kt from the project source and click the green play icon next to the main function, or open the terminal from the project's root directory and launch ./gradlew run (.\gradlew run if using Windows Batch)

To use Android on IntelliJ IDEA, you will need to install the Android plugin and the Android Design Tools plugin. After that you will have to download the Android SDK using the Android SDK Manager. To run your application on Android, you will need to create a virtual device from the Tools menu using the Android device manager.


Create and download your project starter
Create and download your project starter
Import the project in IntelliJ IDEA
Import the project in IntelliJ IDEA
Choose Gradle, and click Finish
Choose Gradle, and click Finish
Run the project
Run the project
Compose multiplatform project started
Compose multiplatform project started

Example: Simple calculator implementation

To dive deeper into Compose Multiplatform concepts and learn it by practice, we will implement in this section a calculator UI. The resulting UI will look like this:

Compose Multiplatform Calculator example

The app's full source code is available on GitHub.

Folder structure

The main code source can be found at composeApp/src. There is 4 modules:

  • androidMain: Android specific code (basically app icons and window positioning)
  • commonMain: shared assets and icons (see Setup and configuration for multiplatform resources)
  • composeMain: shared UI implementation between desktop and Android
  • desktopMain: desktop specific code

Compose Multiplatform folder structure

This project used a slightly different structure than the default one. More information on Kotlin Multiplatform project structure and how to tweak it available here.

composeApp/build.gradle.kts

Main Gradle configuration (you need to know about Gradle with Kotlin syntax as well the Kotlin Multiplatform Gradle plugin for advanced use cases).

Desktop specific code

composeApp/src/desktopMain/kotlin/jetbrains/compose/calculator/Main.kt

package jetbrains.compose.calculator

import androidx.compose.ui.Alignment
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.application
import androidx.compose.ui.window.rememberWindowState
import jetbrains.compose.calculator.resources.Assets
import org.jetbrains.compose.resources.painterResource

fun main() = application {
    Window(
        title = "Calculator",
        state = rememberWindowState(
            width = 400.dp,
            height = 500.dp,
            position = WindowPosition.Aligned(Alignment.Center)
        ),
        icon = painterResource(Assets.WindowIcon),
        onCloseRequest = ::exitApplication) {
        App()
    }
}

You can see some window positioning logic and the desktop icon definition (imported from the the commonMain module). The App logic is defined in the composeMain module.

Android specific code

composeApp/src/androidMain/kotlin/jetbrains/compose/calculator/MainActivity.kt

package jetbrains.compose.calculator

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        enableEdgeToEdge()
        super.onCreate(savedInstanceState)

        setContent {
            Box(
                modifier = Modifier.systemBarsPadding()
            ) {
                App()
            }
        }
    }
}

@Preview
@Composable
fun AppAndroidPreview() {
    App()
}

Some adjustments were made to fit the content correctly within the Android window system.

composeApp/src/androidMain/res/

Android resources such as images, localization and the AndroidManifest.xml for permissions and other configurations.

SVG icons are not supported natively by Android, but you can import them as Vector Assets (only available on the Android Studio IDE).

UI implementation

composeApp/src/composeMain/kotlin/jetbrains/compose/calculator/App.kt

package jetbrains.compose.calculator

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.TextFieldValue
import jetbrains.compose.calculator.resources.lightThemeColors
import jetbrains.compose.calculator.view.DisplayPanel
import jetbrains.compose.calculator.view.Keyboard

@Composable
fun App() {
        MaterialTheme(colors = lightThemeColors) {
            val mainOutput = remember { mutableStateOf(TextFieldValue("0")) }
            Column(Modifier.fillMaxHeight()) {
                DisplayPanel(
                    Modifier.weight(1f),
                    mainOutput
                )
                Keyboard(
                    Modifier.weight(4f),
                    mainOutput
                )
            }
        }
}

This is the main user interface imported by the androidMain and desktopMain modules.

Custom colors were defined for the light theme. You can learn more about available design systems here.

This module is implemented without desktop specific components.

Tooling

The desktop project is already configured with the Compose Hot Reload plugin that makes it to preview directly your code changes after running the project once without restarting. This is is only available for JVM (not for other mobile or web targets).

You can preview your changes in the IDE for Android projects with the @Preview annotation on composable functions using the buttons on the top right area (see the AppAndroidPreview function on Android specific code).

You can change plugin and dependencies versions for Gradle from gradle/libs.versions.toml

References