Compose Multiplatform Project Setup: A Comprehensive Guide

Compose Multiplatform enables developers to build cross-platform applications with a single codebase, leveraging the power of Jetpack Compose for UI development. Setting up a Compose Multiplatform project can seem daunting at first, but with the right steps and tools, it can be a straightforward process. This comprehensive guide walks you through setting up a new Compose Multiplatform project using IntelliJ IDEA.

What is Compose Multiplatform?

Compose Multiplatform is a declarative UI framework developed by JetBrains that allows you to build native desktop, web, and Android applications from a single codebase. It leverages the familiar concepts of Jetpack Compose, making it easier for Android developers to extend their skills to other platforms.

Why Use Compose Multiplatform?

  • Code Reusability: Share a significant portion of your codebase across different platforms.
  • Declarative UI: Benefit from Compose’s intuitive declarative UI programming model.
  • Native Performance: Achieve native-like performance on each platform.
  • Modern Framework: Use a modern, Kotlin-first framework for UI development.

Prerequisites

Before you begin, make sure you have the following installed:

  • IntelliJ IDEA: (Ideally the latest version) The preferred IDE for Kotlin and Compose Multiplatform development.
  • Kotlin Plugin: Ensure the Kotlin plugin is installed and up-to-date in IntelliJ IDEA.
  • JDK (Java Development Kit): Version 11 or higher.
  • Android SDK: If you plan to target Android, ensure the Android SDK is set up.
  • Gradle: Version 7.0 or higher. (Typically bundled with new projects in IntelliJ IDEA)

Step-by-Step Guide to Setting Up a Compose Multiplatform Project

Step 1: Install the JetBrains Compose Multiplatform Plugin

To streamline the setup process, the JetBrains Compose Multiplatform plugin can simplify a lot of the setup steps

  • Open IntelliJ IDEA, go to Settings/Preferences (depending on your OS).
  • Navigate to Plugins.
  • Search for “Compose Multiplatform” in the Marketplace and install the JetBrains provided plugin.
  • Restart the IDEA for the plugin to take affect.

Now that you have this install it allows to easily create Compose Multiplatform project:

Step 2: Create a New Project

  • Open IntelliJ IDEA and click on New Project.
  • In the project wizard, select Compose Multiplatform on the left.
  • Select Compose Multiplatform Application in the middle pane.
  • Configure the Project
    • Name: Enter your project’s name (e.g., MyComposeApp).
    • Location: Choose where to save your project.
    • Package Name: Set the base package name (e.g., com.example.myapp).
    • The templates typically create with “android” as selected and some templates allows desktop, browser and web options too.
  • Click Create. IntelliJ IDEA will generate a new Compose Multiplatform project with the necessary configurations and dependencies.

Step 3: Understand the Project Structure

Once the project is created, familiarize yourself with the directory structure:


MyComposeApp/
├── .gradle/
├── .idea/
├── gradle/
├── src/
│   ├── androidMain/        # Android-specific code
│   │   ├── AndroidManifest.xml
│   │   └── kotlin/
│   │       └── com/example/myapp/
│   │           └── MainActivity.kt
│   ├── commonMain/         # Shared code across platforms
│   │   └── kotlin/
│   │       └── com/example/myapp/
│   │       └── App.kt      # Shared Compose UI code
│   ├── desktopMain/       # Desktop-specific code
│   │   └── kotlin/
│   │       └── main.kt
│   └── iosMain/
│        └── kotlin/
│            └── Main.kt    # Entrypoint for the iOS App (After running on a Apple Silicon based mac.)
├── build.gradle.kts        # Project-level Gradle configuration
├── settings.gradle.kts     # Settings file for Gradle projects
└── ...
  • androidMain: Contains Android-specific code, such as the MainActivity and manifest file.
  • commonMain: Contains shared code that will be used across all platforms (Android, Desktop, Web). This is where most of your Compose UI logic will reside.
  • desktopMain: Contains Desktop-specific code, like the entry point for the desktop application.
  • iosMain: Contains iOS specific code after the code is synced with a apple silicon based mac.
  • build.gradle.kts: Project-level Gradle file for configuration and dependencies.

Step 4: Configure Gradle Files

The generated project usually comes with the necessary Gradle configurations. However, you should review the build.gradle.kts files in the project root and each module (androidMain, commonMain, desktopMain, etc.) to understand the dependencies and build settings.

Project-Level build.gradle.kts

buildscript {
    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
    }
    dependencies {
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.22")
        classpath("com.android.tools.build:gradle:8.4.0")
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://maven.pkg.jetbrains.space/public/p/compose/dev") }
    }
}

tasks.register("clean", Delete::class) {
    delete(rootProject.buildDir)
}
Module-Level build.gradle.kts (commonMain)

dependencies {
    implementation(compose.runtime)
    implementation(compose.foundation)
    implementation(compose.material)
    @OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
    implementation(compose.components.resources)
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")
}

(Check https://github.com/JetBrains/compose-multiplatform-template/blob/main/shared/build.gradle.kts)[example] for other default values like compose.uiToolingPreview.

These configuration files define the necessary dependencies and plugins for building Compose Multiplatform applications. The kotlinx-coroutines-core is very useful for handling cross-platform async operations like file handling (deserializing json or XML for example.).

Step 5: Write Shared UI Code

The commonMain source set is where you’ll write most of your UI code using Jetpack Compose. This code will be shared across all platforms.

Example (commonMain/kotlin/com/example/myapp/App.kt):


import androidx.compose.material.Text
import androidx.compose.runtime.Composable

@Composable
fun App() {
    Text("Hello, Compose Multiplatform!")
}

Step 6: Run the Application on Different Platforms

To run the application on different platforms:

Android
  • Open the androidMain/kotlin/com/example/myapp/MainActivity.kt file.
  • Set the content of the activity to the shared Compose UI.

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import com.example.myapp.App

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            App()
        }
    }
}

Run the application on an Android emulator or device.

Desktop
  • Open the desktopMain/kotlin/main.kt file.
  • Ensure it sets the content to the shared Compose UI.

import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.runtime.Composable
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import com.example.myapp.App

fun main() = application {
    Window(onCloseRequest = ::exitApplication, title = "Compose Multiplatform App") {
        App()
    }
}

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

Run the application from the IDE to see it on the desktop.

Web (Browser)

There may need to configure additional setting as compose web support requires additional steps. Check the docs to see any API updates.

Step 7: Adding Platform-Specific Code

While the goal is to maximize code reuse, you’ll inevitably need to add platform-specific code. Use expect/actual declarations in Kotlin to handle platform-specific implementations.

Example:

In commonMain/kotlin/com/example/myapp/Platform.kt:


expect fun getPlatformName(): String

In androidMain/kotlin/com/example/myapp/Platform.kt:


actual fun getPlatformName(): String {
    return "Android"
}

In desktopMain/kotlin/com/example/myapp/Platform.kt:


actual fun getPlatformName(): String {
    return "Desktop"
}

Step 8: Implement Shared Business Logic

Most multiplatform projects will share complex logic that not limited to simple UI. Kotlin Multiplatform excels here when paired with proper dependency inject framework.

Implement Kotlin common/expect actual pattern along side dependecny injection such as Koin DI(https://insert-koin.io/) in order to get a testable multiplatform setup that allows shared business logic such as Auth.

Best Practices

  • Organize Code: Maintain a clear separation between shared and platform-specific code.
  • Use Dependency Injection: Employ dependency injection to manage platform-specific implementations.
  • Write Tests: Implement unit tests for your shared code to ensure correctness across platforms.
  • Leverage Libraries: Utilize multiplatform libraries like kotlinx.coroutines and kotlinx.serialization.
  • Stay Updated: Keep your dependencies and tooling up to date to benefit from the latest features and bug fixes.

Conclusion

Setting up a Compose Multiplatform project in Jetpack Compose involves creating a new project, understanding the project structure, configuring Gradle files, writing shared UI code, and running the application on different platforms. By following the steps outlined in this guide, you can create a robust and maintainable Compose Multiplatform application. As you become more comfortable with Compose Multiplatform, you’ll discover how to further streamline your cross-platform development workflow, sharing even more code while delivering native performance on each platform.