Mobile Development 21 min read

Kotlin Multiplatform Mobile (KMM): Overview, Setup, Architecture, and Build Process

This article provides a comprehensive guide to Kotlin Multiplatform Mobile (KMM), covering its concepts, advantages over other cross‑platform frameworks, detailed setup steps, project structure, Gradle configuration, code examples for shared and platform‑specific modules, and an in‑depth explanation of the Android and iOS compilation pipelines.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Kotlin Multiplatform Mobile (KMM): Overview, Setup, Architecture, and Build Process

Kotlin Multiplatform Mobile (KMM) is a framework released by JetBrains that enables developers to share business logic across Android and iOS while preserving native UI performance. Unlike other cross‑platform solutions, KMM compiles shared code at build time, resulting in no runtime performance penalty and smaller binary sizes.

The article begins with a brief comparison between KMM and Flutter, highlighting that KMM focuses on shared logic rather than UI rendering, which makes it more suitable for projects that already have native UI implementations.

Preparation

Before creating a KMM project, install the latest Android Studio and Xcode, update JDK, and add the Kotlin Multiplatform Mobile plugin. Verify the environment with brew install kdoctor and kdoctor . Ensure the Android Gradle plugin and Kotlin version are up to date.

Project Structure

A default KMM project contains three modules: androidApp , shared , and iosApp . The shared module holds common code in commonMain , while platform‑specific implementations reside in androidMain and iosMain . The shared module is compiled into an Android AAR and an iOS framework.

pluginManagement {
    repositories {
        google()
        gradlePluginPortal()
        mavenCentral()
    }
}

dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
    }
}

rootProject.name = "My_Application"
include(":androidApp")
include(":shared")

The Gradle configuration for the shared module applies the multiplatform plugin and defines targets for Android and iOS:

plugins {
    kotlin("multiplatform")
    id("com.android.library")
}

kotlin {
    android()
    iosX64()
    iosArm64()
    iosSimulatorArm64()
}

Source sets are configured to include common dependencies (e.g., kotlinx‑datetime, coroutines, Ktor) and platform‑specific libraries:

kotlin {
    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
                implementation("io.ktor:ktor-client-core:$ktorVersion")
                implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
                implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
            }
        }
        val androidMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-android:$ktorVersion")
            }
        }
        val iosMain by creating {
            dependencies {
                implementation("io.ktor:ktor-client-darwin:$ktorVersion")
            }
        }
    }
}

Demo Application

The demo creates a simple Greeting class in the shared module that uses an expect declaration to obtain the platform name, with actual implementations for Android and iOS:

class Greeting {
    private val platform: Platform = getPlatform()
    fun greeting(): String = "Hello, ${platform.name}!"
}

interface Platform {
    val name: String
}

expect fun getPlatform(): Platform

Android implementation:

class AndroidPlatform : Platform {
    override val name: String = "Android ${android.os.Build.VERSION.SDK_INT}"
}

actual fun getPlatform(): Platform = AndroidPlatform()

iOS implementation:

class IOSPlatform: Platform {
    override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
}

actual fun getPlatform(): Platform = IOSPlatform()

The Android app uses Jetpack Compose to display the greeting, while the iOS app uses SwiftUI.

Compilation Process – Android

The Android AAR is built by the KotlinMultiplatformPlugin , which creates a KotlinAndroidTarget . The plugin dynamically applies Android‑specific configuration, registers a KotlinCompile task, and wires it with the Java compile task. The compile task ultimately invokes GradleCompilerRunnerWithWorkers , which runs the Kotlin compiler (either via daemon, in‑process, or out‑of‑process execution). The compiler uses the ASM library to generate Java bytecode.

override fun apply(project: Project) {
    // ...
    setupDefaultPresets(project)
    customizeKotlinDependencies(project)
    configureSourceSets(project)
    // ...
}

During execution, KotlinCompile calls callCompilerAsync , which creates a GradleCompilerRunner . The runner creates a GradleCompilerRunnerWithWorkers instance that eventually calls runJvmCompilerAsync . The compilation is performed by K2JVMCompiler , which generates bytecode via KotlinToJVMBytecodeCompiler.compileModules and ASM MethodVisitor calls.

Compilation Process – iOS

For iOS, the plugin creates a KotlinNativeTarget using KotlinNativeTargetPreset . The target configures binaries, creates a KotlinNativeLink task, and, if supported, a FatFrameworkTask that merges multiple architecture binaries into a single framework. The final framework is packaged with headers, module files, and plists.

override fun configureTarget(target: T) {
    configureBinaries(target)
    configureFrameworkExport(target)
    configureCInterops(target)
    if (target.konanTarget.family.isAppleFamily) {
        registerEmbedAndSignAppleFrameworkTasks(target)
    }
    // ...
}

The FatFrameworkTask creates the framework by merging binaries, headers, and resources:

@TaskAction
protected fun createFatFramework() {
    val outFramework = fatFrameworkLayout
    outFramework.mkdirs()
    mergeBinaries(outFramework.binary)
    mergeHeaders(outFramework.header)
    createModuleFile(outFramework.moduleFile, fatFrameworkName)
    mergePlists(outFramework.infoPlist, fatFrameworkName)
    mergeDSYM()
}

Conclusion

KMM allows developers to share business logic between Android and iOS without sacrificing native performance. While still maturing, its low learning curve for Android developers and seamless Gradle integration make it a viable option for incremental adoption in mobile projects.

References

https://kotlinlang.org/docs/multiplatform-mobile-getting-started.html

https://www.jianshu.com/p/bd0cf9b2193c

https://blog.csdn.net/rain_butterfly/article/details/87941589

mobile developmentiOSAndroidGradleKotlinMultiplatformKMM
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.