Kotlin Multiplatform Mobile (KMM): Panduan Lengkap dari Setup hingga Hello World
Kotlin Multiplatform Mobile (KMM) adalah teknologi dari JetBrains yang memungkinkan kamu untuk share business logic antara Android dan iOS sambil tetap menggunakan native UI untuk masing-masing platform. Dengan KMM, kamu bisa menulis network layer, data persistence, dan business logic sekali dalam Kotlin, kemudian gunakan di kedua platform.
Apa itu Kotlin Multiplatform Mobile?
KMM adalah subset dari Kotlin Multiplatform yang fokus pada mobile development. Berbeda dengan Flutter atau React Native yang juga share UI layer, KMM hanya share business logic layer. Ini memberikan flexibility untuk membangun truly native UI menggunakan SwiftUI untuk iOS dan Jetpack Compose untuk Android, sambil share core application logic.
Konsep Utama:
- Shared Module: Kotlin code yang di-compile untuk Android (JVM) dan iOS (Native)
- Platform-Specific Code: Native code untuk functionality yang platform-specific
- Expect/Actual Mechanism: API untuk define platform-specific implementations
- Native UI: SwiftUI untuk iOS, Jetpack Compose untuk Android
Keunggulan KMM:
- Native UI & Performance: True native UI dengan native performance
- Gradual Adoption: Bisa integrate ke existing native apps
- Shared Business Logic: Write once, use everywhere untuk core logic
- Type Safety: Kotlin's type system across platforms
- Existing Team Skills: Android developers bisa contribute ke iOS logic
- No Bridge Overhead: Direct interop, no bridge layer
Kapan Menggunakan KMM:
- Team sudah punya native mobile developers (Android/iOS)
- Ingin maintain native UI/UX per platform
- Business logic complex dan ingin share
- Want to avoid platform limitations dari cross-platform frameworks
- Already have native apps dan ingin share logic gradually
Persiapan Sistem
Requirements:
Untuk macOS (Recommended untuk iOS development):
- macOS 12.0 (Monterey) atau lebih baru
- Minimum 8 GB RAM (16 GB direkomendasikan)
- 30 GB ruang disk kosong
- Xcode 14.0 atau lebih baru
- Android Studio (latest stable)
- CocoaPods (untuk iOS dependencies)
- JDK 11 atau lebih baru
Untuk Windows/Linux (Android only):
- Windows 10/11 atau Linux (64-bit)
- Minimum 8 GB RAM (16 GB direkomendasikan)
- 20 GB ruang disk kosong
- Android Studio (latest stable)
- JDK 11 atau lebih baru
Note: Untuk develop iOS app dengan KMM, kamu harus menggunakan macOS. Windows/Linux hanya bisa develop Android side.
Bagian 1: Setup Development Environment
Langkah 1: Install Android Studio
Download dan install Android Studio dari developer.android.com/studio (opens in a new tab).

Follow instalasi wizard seperti di tutorial Android Studio sebelumnya. Pastikan terinstall:
- Android SDK (API 33 atau lebih baru)
- Android SDK Build-Tools
- Android Emulator
- SDK Platform-Tools
Langkah 2: Install Kotlin Multiplatform Plugin
- Buka Android Studio
- Go to Preferences/Settings (macOS: Cmd+, / Windows: Ctrl+Alt+S)
- Navigate ke Plugins
- Search "Kotlin Multiplatform Mobile"
- Click Install

- Restart Android Studio setelah instalasi
Plugin ini menyediakan:
- KMM project templates
- Kotlin/Native compilation support
- iOS framework generation
- Integration dengan Xcode
Langkah 3: Setup Xcode (macOS Only)
Jika di macOS, install Xcode dari App Store (seperti di tutorial Xcode sebelumnya).
Setelah install, verify installation:
xcode-select --print-pathOutput harus menunjukkan path ke Xcode:
/Applications/Xcode.app/Contents/DeveloperAccept license:
sudo xcodebuild -license acceptInstall Command Line Tools:
xcode-select --install
Langkah 4: Install CocoaPods (macOS Only)
KMM menggunakan CocoaPods untuk integrate Kotlin framework ke iOS project.
sudo gem install cocoapods
Verify installation:
pod --versionOutput menampilkan versi CocoaPods, misalnya 1.14.3.
Langkah 5: Install KDoctor (Recommended)
KDoctor adalah tool untuk diagnose KMM setup. Install via Homebrew (macOS) atau manual:
macOS:
brew install kdoctorManual (semua platform): Download dari GitHub releases (opens in a new tab).
Run KDoctor untuk check environment:
kdoctor
KDoctor akan check:
- ✓ JDK installation
- ✓ Android Studio setup
- ✓ Xcode (macOS)
- ✓ CocoaPods (macOS)
- ✗ Any missing components
Fix any issues yang di-report oleh KDoctor.
Langkah 6: Verify Java Installation
KMM requires JDK 11 atau lebih baru.
java -version
Jika belum install atau versi lama, download dari:
- Adoptium (opens in a new tab) - JDK 17 LTS (recommended)
- Oracle JDK (opens in a new tab)
macOS (via Homebrew):
brew install openjdk@17Bagian 2: Membuat Project KMM
Langkah 7: Create New KMM Project
Ada beberapa cara untuk create KMM project:
Option 1: Menggunakan KMM Wizard (Recommended)
- Buka Android Studio
- Select File > New > New Project
- Di tab sebelah kiri, pilih Kotlin Multiplatform
- Pilih Kotlin Multiplatform App

- Click Next
Option 2: Menggunakan Kotlin Multiplatform Wizard Website
Visit kmp.jetbrains.com (opens in a new tab) dan follow wizard online.

Langkah 8: Configure Project
Di project configuration screen:

Name: HelloWorldKMM
- Nama aplikasi
Package name: com.example.helloworldkmm
- Bundle identifier untuk app
Save location: Pilih folder untuk project
Project configuration options:
iOS Framework Distribution:
- Regular framework: Standard framework (pilih ini untuk tutorial)
- CocoaPods dependency manager: Integrate via CocoaPods
- Shared via SwiftPM: Swift Package Manager
Android Application:
- ✓ Check ini untuk generate Android app
iOS Application:
- ✓ Check ini untuk generate iOS app (macOS only)
Configuration:
- Pilih Kotlin sebagai Android DSL
- Pilih API level minimum (misalnya 24)
Click Finish untuk create project.
Langkah 9: Project Structure
Android Studio akan create project dan sync dependencies. Ini memakan waktu beberapa menit.

Setelah selesai, explore project structure:

HelloWorldKMM/
├── androidApp/ # Android application
│ ├── src/
│ │ └── main/
│ │ ├── AndroidManifest.xml
│ │ └── kotlin/
│ │ └── MainActivity.kt
│ └── build.gradle.kts
├── iosApp/ # iOS application (macOS only)
│ ├── iosApp/
│ │ ├── ContentView.swift
│ │ └── iOSApp.swift
│ └── iosApp.xcodeproj
├── shared/ # Shared Kotlin code
│ ├── src/
│ │ ├── commonMain/ # Common code
│ │ │ └── kotlin/
│ │ │ └── Greeting.kt
│ │ ├── androidMain/ # Android-specific code
│ │ │ └── kotlin/
│ │ ├── iosMain/ # iOS-specific code
│ │ │ └── kotlin/
│ │ └── commonTest/ # Common tests
│ └── build.gradle.kts
├── gradle/
├── build.gradle.kts
└── settings.gradle.ktsKey Components:
- shared/: Modul yang berisi shared Kotlin code
- commonMain/: Code yang berjalan di semua platform
- androidMain/: Android-specific implementations
- iosMain/: iOS-specific implementations
- androidApp/: Native Android application (Jetpack Compose)
- iosApp/: Native iOS application (SwiftUI)
Langkah 10: Explore Shared Module
Buka file shared/src/commonMain/kotlin/Greeting.kt:

package com.example.helloworldkmm
class Greeting {
private val platform: Platform = getPlatform()
fun greet(): String {
return "Hello, ${platform.name}!"
}
}
interface Platform {
val name: String
}
expect fun getPlatform(): PlatformPenjelasan Code:
- Greeting class: Class yang bisa digunakan dari Android dan iOS
- Platform interface: Define contract untuk platform-specific info
- expect fun getPlatform(): Declaration untuk function yang akan di-implement per platform
Ini adalah expect/actual mechanism - core concept di KMM.
Langkah 11: Platform-Specific Implementations
Android Implementation - shared/src/androidMain/kotlin/Platform.android.kt:
package com.example.helloworldkmm
import android.os.Build
class AndroidPlatform : Platform {
override val name: String =
"Android ${Build.VERSION.SDK_INT}"
}
actual fun getPlatform(): Platform = AndroidPlatform()iOS Implementation - shared/src/iosMain/kotlin/Platform.ios.kt:
package com.example.helloworldkmm
import platform.UIKit.UIDevice
class IOSPlatform: Platform {
override val name: String =
UIDevice.currentDevice.systemName() + " " +
UIDevice.currentDevice.systemVersion
}
actual fun getPlatform(): Platform = IOSPlatform()
Dengan expect/actual, kamu define interface di commonMain, dan provide platform-specific implementation di androidMain dan iosMain.
Langkah 12: Android Application Code
Buka androidApp/src/main/kotlin/MainActivity.kt:

package com.example.helloworldkmm.android
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.example.helloworldkmm.Greeting
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApplicationTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
GreetingView(Greeting().greet())
}
}
}
}
}
@Composable
fun GreetingView(text: String) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = text,
style = MaterialTheme.typography.headlineMedium
)
}
}Android app menggunakan Jetpack Compose dan call Greeting().greet() dari shared module.
Langkah 13: iOS Application Code (macOS Only)
Buka iosApp/iosApp/ContentView.swift:

import SwiftUI
import shared
struct ContentView: View {
let greet = Greeting().greet()
var body: some View {
VStack {
Text(greet)
.font(.largeTitle)
.padding()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}iOS app menggunakan SwiftUI dan import shared framework untuk access Kotlin code.
Langkah 14: Customize Shared Code
Mari customize greeting. Edit shared/src/commonMain/kotlin/Greeting.kt:
package com.example.helloworldkmm
class Greeting {
private val platform: Platform = getPlatform()
fun greet(): String {
return "Hello World!\nSelamat datang di ${platform.name}"
}
fun getFullGreeting(): String {
return """
🎉 Hello World! 🎉
Selamat datang di Kotlin Multiplatform Mobile
Platform: ${platform.name}
Shared business logic, native UI!
""".trimIndent()
}
}
interface Platform {
val name: String
}
expect fun getPlatform(): Platform
Save file (Cmd/Ctrl + S).
Bagian 3: Running Android App
Langkah 15: Build Shared Module
Sebelum run apps, build shared module:
./gradlew :shared:buildAtau di Android Studio: Build > Make Project (Cmd+F9 / Ctrl+F9)

Build process akan:
- Compile Kotlin code untuk Android (JVM)
- Compile Kotlin code untuk iOS (Native)
- Generate iOS framework
- Package artifacts
Langkah 16: Start Android Emulator
Launch Android emulator seperti di tutorial Android Studio sebelumnya.

Atau via command line:
emulator -list-avds
emulator -avd Pixel_6_API_33Langkah 17: Run Android App
Di Android Studio:
- Select androidApp configuration dari dropdown
- Select emulator atau device
- Click Run button (▶) atau press Shift+F10

Atau via command line:
./gradlew :androidApp:installDebugBuild akan:
- Compile shared Kotlin module
- Build Android app
- Install ke emulator/device
- Launch app
Langkah 18: App Running di Android
Aplikasi akan launch di Android emulator.

Kamu akan melihat:
- "Hello World!"
- "Selamat datang di Android [version]"
- Clean Material Design 3 UI
Greeting text berasal dari shared Kotlin module, tapi UI adalah native Jetpack Compose!
Langkah 19: Update Android UI
Let's improve Android UI. Edit androidApp/src/main/kotlin/MainActivity.kt:
@Composable
fun GreetingView(text: String) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Icon(
imageVector = Icons.Default.Star,
contentDescription = null,
modifier = Modifier.size(80.dp),
tint = MaterialTheme.colorScheme.primary
)
Spacer(modifier = Modifier.height(24.dp))
Text(
text = text,
style = MaterialTheme.typography.headlineMedium,
textAlign = TextAlign.Center
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "Native UI, Shared Logic",
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}Jangan lupa import:
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Star
import androidx.compose.ui.text.style.TextAlignHot reload atau rebuild app untuk melihat perubahan.

Bagian 4: Running iOS App (macOS Only)
Langkah 20: Open iOS Project di Xcode
Di terminal, navigate ke project directory dan open Xcode:
cd HelloWorldKMM
open iosApp/iosApp.xcodeprojAtau di Android Studio, right-click folder iosApp dan pilih Open In > Xcode.

Langkah 21: Configure iOS Project Signing
Di Xcode:
- Select project "iosApp" di navigator
- Select target "iosApp"
- Go to Signing & Capabilities tab
- Check Automatically manage signing
- Select your Team (Apple ID)

Xcode akan automatically generate provisioning profile.
Langkah 22: Build Shared Framework untuk iOS
Sebelum run iOS app, pastikan shared framework ter-build:
./gradlew :shared:embedAndSignAppleFrameworkForXcodeAtau di Android Studio:
- Open Gradle tool window (View > Tool Windows > Gradle)
- Navigate ke shared > Tasks > build
- Run embedAndSignAppleFrameworkForXcode

Ini akan compile Kotlin code ke native iOS framework.
Langkah 23: Run iOS App di Simulator
Di Xcode:
- Select iOS Simulator dari scheme selector (misalnya iPhone 15)
- Click Run button (▶) atau press Cmd+R

Xcode akan:
- Build iOS application
- Link dengan shared framework
- Launch simulator
- Install dan run app
Langkah 24: App Running di iOS
iOS Simulator akan launch dan menampilkan aplikasi.

Kamu akan melihat greeting yang sama, tapi dengan iOS native UI (SwiftUI)!
Text berasal dari shared Kotlin module yang sama seperti Android.
Langkah 25: Update iOS UI
Mari improve iOS UI. Edit iosApp/iosApp/ContentView.swift:
import SwiftUI
import shared
struct ContentView: View {
let greeting = Greeting()
var body: some View {
VStack(spacing: 20) {
Image(systemName: "star.fill")
.resizable()
.scaledToFit()
.frame(width: 80, height: 80)
.foregroundColor(.blue)
Text(greeting.getFullGreeting())
.font(.title2)
.multilineTextAlignment(.center)
.padding()
Text("Native UI, Shared Logic")
.font(.body)
.foregroundColor(.secondary)
}
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Build and run (Cmd+R) untuk melihat perubahan.

Bagian 5: Shared Business Logic
Sekarang mari demonstrate power of KMM dengan add shared business logic.
Langkah 26: Create Shared Data Class
Buat file baru di shared/src/commonMain/kotlin/models/User.kt:
package com.example.helloworldkmm.models
data class User(
val id: Int,
val name: String,
val email: String
)Langkah 27: Create Shared Repository
Buat file shared/src/commonMain/kotlin/repository/UserRepository.kt:
package com.example.helloworldkmm.repository
import com.example.helloworldkmm.models.User
class UserRepository {
// Simulated data - in real app, this would be from API/Database
private val users = listOf(
User(1, "John Doe", "john@example.com"),
User(2, "Jane Smith", "jane@example.com"),
User(3, "Bob Johnson", "bob@example.com")
)
fun getAllUsers(): List<User> {
return users
}
fun getUserById(id: Int): User? {
return users.find { it.id == id }
}
fun searchUsers(query: String): List<User> {
return users.filter {
it.name.contains(query, ignoreCase = true) ||
it.email.contains(query, ignoreCase = true)
}
}
}
Key Point: Repository ini ditulis sekali, tapi bisa digunakan dari Android dan iOS!
Langkah 28: Create Shared ViewModel Logic
Buat file shared/src/commonMain/kotlin/viewmodel/UserViewModel.kt:
package com.example.helloworldkmm.viewmodel
import com.example.helloworldkmm.models.User
import com.example.helloworldkmm.repository.UserRepository
class UserViewModel {
private val repository = UserRepository()
fun getUsers(): List<User> {
return repository.getAllUsers()
}
fun getUserDetails(userId: Int): User? {
return repository.getUserById(userId)
}
fun search(query: String): List<User> {
return if (query.isBlank()) {
repository.getAllUsers()
} else {
repository.searchUsers(query)
}
}
}Business logic sekarang ada di shared module!
Langkah 29: Use Shared Code di Android
Update androidApp/src/main/kotlin/MainActivity.kt:
package com.example.helloworldkmm.android
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.example.helloworldkmm.Greeting
import com.example.helloworldkmm.viewmodel.UserViewModel
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApplicationTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
UserListScreen()
}
}
}
}
}
@Composable
fun UserListScreen() {
val viewModel = remember { UserViewModel() }
val users = remember { viewModel.getUsers() }
Column(modifier = Modifier.fillMaxSize()) {
// Header
Text(
text = Greeting().greet(),
style = MaterialTheme.typography.headlineSmall,
modifier = Modifier.padding(16.dp)
)
Divider()
// User List
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
items(users) { user ->
UserCard(user)
}
}
}
}
@Composable
fun UserCard(user: com.example.helloworldkmm.models.User) {
Card(
modifier = Modifier.fillMaxWidth()
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = user.name,
style = MaterialTheme.typography.titleMedium
)
Text(
text = user.email,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
Langkah 30: Use Shared Code di iOS
Update iosApp/iosApp/ContentView.swift:
import SwiftUI
import shared
struct ContentView: View {
let greeting = Greeting()
let viewModel = UserViewModel()
var body: some View {
NavigationView {
VStack {
// Header
Text(greeting.greet())
.font(.headline)
.padding()
Divider()
// User List
List(viewModel.getUsers(), id: \.id) { user in
UserRow(user: user)
}
.listStyle(PlainListStyle())
}
.navigationTitle("KMM Demo")
}
}
}
struct UserRow: View {
let user: User
var body: some View {
VStack(alignment: .leading, spacing: 4) {
Text(user.name)
.font(.headline)
Text(user.email)
.font(.subheadline)
.foregroundColor(.secondary)
}
.padding(.vertical, 4)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Magic: Business logic (UserViewModel, UserRepository, User model) adalah code yang sama di kedua platform!
Bagian 6: Expect/Actual Pattern
Mari explore expect/actual pattern lebih dalam dengan contoh praktis.
Langkah 31: Create Platform-Specific UUID
Buat shared/src/commonMain/kotlin/utils/UUIDGenerator.kt:
package com.example.helloworldkmm.utils
// Expect declaration
expect fun generateUUID(): String
class UUIDGenerator {
fun createId(): String {
return generateUUID()
}
}Langkah 32: Android Implementation
Buat shared/src/androidMain/kotlin/utils/UUIDGenerator.android.kt:
package com.example.helloworldkmm.utils
import java.util.UUID
// Actual implementation untuk Android
actual fun generateUUID(): String {
return UUID.randomUUID().toString()
}Langkah 33: iOS Implementation
Buat shared/src/iosMain/kotlin/utils/UUIDGenerator.ios.kt:
package com.example.helloworldkmm.utils
import platform.Foundation.NSUUID
// Actual implementation untuk iOS
actual fun generateUUID(): String {
return NSUUID().UUIDString()
}
Sekarang kamu bisa use UUIDGenerator().createId() dari common code, dan akan use platform-specific implementation!
Bagian 7: Network Request dengan Ktor
Mari add real networking capability menggunakan Ktor (HTTP client dari Kotlin).
Langkah 34: Add Ktor Dependencies
Edit shared/build.gradle.kts, add di sourceSets:
val commonMain by getting {
dependencies {
implementation("io.ktor:ktor-client-core:2.3.7")
implementation("io.ktor:ktor-client-content-negotiation:2.3.7")
implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.7")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2")
}
}
val androidMain by getting {
dependencies {
implementation("io.ktor:ktor-client-android:2.3.7")
}
}
val iosMain by getting {
dependencies {
implementation("io.ktor:ktor-client-darwin:2.3.7")
}
}Add plugin di top file:
plugins {
// ... existing plugins
kotlin("plugin.serialization") version "1.9.21"
}
Sync project untuk download dependencies.
Langkah 35: Create API Service
Buat shared/src/commonMain/kotlin/api/ApiService.kt:
package com.example.helloworldkmm.api
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.request.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.json.Json
class ApiService {
private val client = HttpClient {
install(ContentNegotiation) {
json(Json {
ignoreUnknownKeys = true
isLenient = true
})
}
}
suspend fun fetchGreeting(): String {
return try {
val response: String = client.get("https://api.example.com/greeting").body()
response
} catch (e: Exception) {
"Error: ${e.message}"
}
}
}Key Point: Ktor client code ini works di Android dan iOS!
Troubleshooting Common Issues
Issue 1: "Could not find shared framework"
Error: iOS app tidak bisa find shared framework
Solusi:
# Clean dan rebuild shared module
./gradlew :shared:clean
./gradlew :shared:build
# Atau di Xcode
# Product > Clean Build Folder (Shift+Cmd+K)Issue 2: CocoaPods Integration Failed
Error: Pod install fails atau framework tidak ter-link
Solusi:
cd iosApp
pod deintegrate
pod installCheck Podfile memiliki reference ke shared framework.
Issue 3: Kotlin/Native Compilation Failed
Error: Cannot compile for iOS target
Solusi:
- Check Xcode Command Line Tools installed:
xcode-select --install- Verify KDoctor output:
kdoctor- Clean Kotlin/Native cache:
rm -rf ~/.konanIssue 4: "No signature of method" Gradle Error
Error: Gradle sync fails dengan method signature error
Solusi:
- Update Gradle version di
gradle/wrapper/gradle-wrapper.properties - Update Android Gradle Plugin di root
build.gradle.kts - Invalidate caches: File > Invalidate Caches / Restart
Issue 5: iOS Framework Not Updated
Error: Changes di shared module tidak reflect di iOS app
Solusi:
# Rebuild framework
./gradlew :shared:embedAndSignAppleFrameworkForXcode
# Di Xcode
# Product > Clean Build Folder
# Product > Build (Cmd+B)Issue 6: Android Build Failed - Duplicate Class
Error: Duplicate class found error
Solusi: Clean project:
./gradlew clean
./gradlew :shared:clean
./gradlew :androidApp:cleanCheck for conflicting dependencies di build.gradle.kts.
Tips dan Best Practices
1. Project Structure
Organize shared code dengan baik:
shared/src/
├── commonMain/
│ └── kotlin/
│ ├── models/ # Data models
│ ├── repository/ # Data access layer
│ ├── usecase/ # Business logic
│ ├── api/ # Network layer
│ └── utils/ # Utilities
├── androidMain/
│ └── kotlin/
│ └── platform/ # Android-specific impl
└── iosMain/
└── kotlin/
└── platform/ # iOS-specific impl2. Dependency Injection
Untuk larger projects, use dependency injection:
// Koin (popular DI framework untuk KMM)
dependencies {
implementation("io.insert-koin:koin-core:3.5.0")
}3. Testing
Write tests di commonTest:
// shared/src/commonTest/kotlin/UserRepositoryTest.kt
class UserRepositoryTest {
@Test
fun testGetAllUsers() {
val repo = UserRepository()
val users = repo.getAllUsers()
assertEquals(3, users.size)
}
}Run tests:
./gradlew :shared:test4. Coroutines untuk Async
Use Kotlin Coroutines untuk async operations:
class ApiService {
suspend fun fetchData(): Result<List<User>> {
return withContext(Dispatchers.Default) {
// Network call
}
}
}5. Error Handling
Implement proper error handling:
sealed class Result<out T> {
data class Success<T>(val data: T) : Result<T>()
data class Error(val exception: Exception) : Result<Nothing>()
object Loading : Result<Nothing>()
}6. Platform-Specific APIs
Use expect/actual untuk platform APIs:
// Common
expect class FileReader {
fun readFile(path: String): String
}
// Android
actual class FileReader {
actual fun readFile(path: String): String {
// Use java.io.File
}
}
// iOS
actual class FileReader {
actual fun readFile(path: String): String {
// Use NSFileManager
}
}7. Gradle Configuration
Optimize build dengan proper caching:
// shared/build.gradle.kts
kotlin {
android()
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach {
it.binaries.framework {
baseName = "shared"
isStatic = true // Improve build performance
}
}
}8. Version Catalogs
Use version catalogs untuk manage dependencies:
# gradle/libs.versions.toml
[versions]
ktor = "2.3.7"
coroutines = "1.7.3"
[libraries]
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }Advanced Topics
1. SQLDelight untuk Database
Share database logic dengan SQLDelight:
// shared/build.gradle.kts
plugins {
id("com.squareup.sqldelight") version "2.0.0"
}
sqldelight {
databases {
create("AppDatabase") {
packageName.set("com.example.helloworldkmm.db")
}
}
}2. MVVM Architecture
Implement MVVM pattern:
// Common ViewModel
class UserListViewModel {
private val repository = UserRepository()
private val _users = MutableStateFlow<List<User>>(emptyList())
val users: StateFlow<List<User>> = _users
fun loadUsers() {
viewModelScope.launch {
_users.value = repository.getAllUsers()
}
}
}3. Image Loading
Share image loading logic:
// Use Kamel for KMM
dependencies {
implementation("media.kamel:kamel-image:0.9.0")
}4. Navigation
Consider architecture untuk navigation:
- Android: Jetpack Navigation Compose
- iOS: SwiftUI NavigationStack
- Share: Navigation state dan logic di shared module
Next Steps
1. Master Kotlin
Deep dive into Kotlin features:
- Coroutines dan Flow
- Sealed classes dan when expressions
- Extension functions
- DSL builders
- Delegates
2. Platform Interop
Learn platform interoperability:
- Calling iOS frameworks dari Kotlin
- Exporting Kotlin to Swift
- Memory management
- Threading model
3. State Management
Explore state management solutions:
- MVIKotlin - MVI framework untuk KMM
- Decompose - Lifecycle-aware components
- Moko MVVM - MVVM untuk KMM
4. Networking & Serialization
Master networking:
- Ktor client advanced features
- Authentication dan authorization
- WebSocket support
- GraphQL dengan Apollo Kotlin
5. Local Storage
Implement data persistence:
- SQLDelight - SQL database
- Realm - Object database
- Multiplatform Settings - Key-value storage
- DataStore - Type-safe storage
6. Testing
Comprehensive testing:
- Unit tests di commonTest
- Platform-specific tests
- Integration tests
- UI tests per platform
7. CI/CD
Setup automation:
- GitHub Actions untuk KMM
- Automated testing
- Framework building
- App distribution
Resources
Official Documentation
- Kotlin Multiplatform (opens in a new tab)
- KMM Documentation (opens in a new tab)
- Kotlin for iOS (opens in a new tab)
- Ktor Documentation (opens in a new tab)
Learning Resources
- KMM Samples (opens in a new tab) - Official samples
- Touchlab Resources (opens in a new tab) - KMM expertise
- KMM Awesome (opens in a new tab) - Curated list
Libraries
- Networking: Ktor Client
- Database: SQLDelight, Realm
- DI: Koin
- Serialization: kotlinx.serialization
- Settings: Multiplatform Settings
- DateTime: kotlinx-datetime
- Image Loading: Kamel
- Logging: Kermit, Napier
Communities
- Kotlin Slack (opens in a new tab) - #multiplatform channel
- KotlinConf (opens in a new tab)
- /r/Kotlin (opens in a new tab)
- Stack Overflow KMM Tag (opens in a new tab)
Blogs & Tutorials
- Touchlab Blog (opens in a new tab)
- JetBrains Blog (opens in a new tab)
- ProAndroidDev (opens in a new tab)
Penutup
Selamat! Kamu telah berhasil setup Kotlin Multiplatform Mobile environment dan membuat aplikasi yang share business logic antara Android dan iOS sambil maintain native UI untuk masing-masing platform.
KMM adalah approach yang unique dan powerful untuk mobile development. Berbeda dengan Flutter atau React Native yang share everything termasuk UI, KMM memberikan flexibility untuk maintain truly native UI experiences sambil share core business logic, data layer, dan utilities.
Keuntungan KMM:
- Gradual Adoption - Bisa integrate ke existing native apps step by step
- Native Performance - No bridge, direct interop
- Type Safety - Kotlin's strong typing across platforms
- Leverage Existing Skills - Android devs bisa contribute ke iOS logic
- Best of Both Worlds - Native UI dengan shared logic
When to Choose KMM:
- Team punya Android developers yang ingin expand ke iOS
- Already have native apps dan ingin share logic
- Native UI/UX per platform adalah priority
- Want maximum performance dan platform integration
- Complex business logic yang ingin di-share
KMM masih relatively new dibanding React Native atau Flutter, tapi rapidly growing dengan strong support dari JetBrains dan Google. Banyak companies sudah adopt KMM untuk production apps.
Yang terpenting, KMM bukan replacement untuk native development - it's enhancement. Kamu still write native UI code, tapi share valuable business logic yang otherwise harus di-duplicate.
Start small, share logic incrementally, dan enjoy benefits dari write once, use everywhere untuk business logic sambil maintain native UI excellence!
Happy Kotlin Multiplatform Coding!