Using KMP, a list Screen for both Android & iOS
May 31, 2025

Overview
- Shared Module: Contains business logic and data models.
- Android App: Uses Jetpack Compose or traditional views to display the list.
- iOS App: Uses SwiftUI or UIKit and interacts with shared code via KMP.
Below is a basic example using:
- Kotlin Multiplatform
- Ktor for data fetching (mocked in this case)
- Android using Jetpack Compose
- iOS using SwiftUI
Step-by-step Kotlin KMP List Example
1. Project Structure
MyKMPApp/
├── androidApp/ # Android native app
├── iosApp/ # iOS native app (Swift)
├── shared/ # KMP shared module
└── build.gradle.kts # Root Gradle file
2. shared
Module Code
build.gradle.kts
(shared):
kotlin {
android()
iosX64()
iosArm64()
iosSimulatorArm64()
sourceSets {
val commonMain by getting {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")
}
}
val androidMain by getting
val iosMain by creating {
dependsOn(commonMain)
}
iosX64Main.dependsOn(iosMain)
iosArm64Main.dependsOn(iosMain)
iosSimulatorArm64Main.dependsOn(iosMain)
}
}
commonMain/ListRepository.kt
:
package com.example.shared
data class Item(val id: Int, val title: String)
class ListRepository {
fun getItems(): List {
return List(20) { Item(it, “Item #$it”) }
}
}
3. Android App (androidApp
)
build.gradle.kts
:
dependencies {
implementation(project(“:shared”))
implementation(“androidx.activity:activity-compose:1.9.0”)
implementation(“androidx.compose.ui:ui:1.6.4”)
implementation(“androidx.compose.material3:material3:1.2.1”)
}
MainActivity.kt:
package com.example.androidApp
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.*
import androidx.compose.runtime.*
import com.example.shared.ListRepository
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val items = remember { ListRepository().getItems() }
MaterialTheme {
LazyColumn {
items(items) { item ->
Text(text = item.title, style = MaterialTheme.typography.bodyLarge)
}
}
}
}
}
}
4. iOS App (iosApp
with SwiftUI)
ContentView.swift
:
import SwiftUI
import shared
struct ContentView: View {
let items: [Item] = ListRepository().getItems().map { $0 as! Item }
var body: some View {
NavigationView {
List(items, id: \.id) { item in
Text(item.title)
}
.navigationTitle("KMP List")
}
}
}
iosApp.swift
:
import SwiftUI
@main
struct iOSApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
5. Root settings.gradle.kts
and build.gradle.kts
settings.gradle.kts
include(“:shared”)
include(“:androidApp”)
build.gradle.kts
buildscript {
dependencies {
classpath(“org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.22”)
}
}
You’ll get a shared list logic (ListRepository
) that is rendered via:
- Jetpack Compose on Android
- SwiftUI on iOS