Mobile Application Development
Kotlin Multiplatform Mobile (KMM)

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).

Android Studio download page

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

  1. Buka Android Studio
  2. Go to Preferences/Settings (macOS: Cmd+, / Windows: Ctrl+Alt+S)
  3. Navigate ke Plugins
  4. Search "Kotlin Multiplatform Mobile"
  5. Click Install

Android Studio Plugins menampilkan KMM plugin

  1. 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-path

Output harus menunjukkan path ke Xcode:

/Applications/Xcode.app/Contents/Developer

Accept license:

sudo xcodebuild -license accept

Install Command Line Tools:

xcode-select --install

Dialog instalasi Xcode Command Line Tools

Langkah 4: Install CocoaPods (macOS Only)

KMM menggunakan CocoaPods untuk integrate Kotlin framework ke iOS project.

sudo gem install cocoapods

Terminal menampilkan instalasi CocoaPods

Verify installation:

pod --version

Output 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 kdoctor

Manual (semua platform): Download dari GitHub releases (opens in a new tab).

Run KDoctor untuk check environment:

kdoctor

Terminal menampilkan output 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

Terminal menampilkan Java version

Jika belum install atau versi lama, download dari:

macOS (via Homebrew):

brew install openjdk@17

Bagian 2: Membuat Project KMM

Langkah 7: Create New KMM Project

Ada beberapa cara untuk create KMM project:

Option 1: Menggunakan KMM Wizard (Recommended)

  1. Buka Android Studio
  2. Select File > New > New Project
  3. Di tab sebelah kiri, pilih Kotlin Multiplatform
  4. Pilih Kotlin Multiplatform App

Android Studio New Project wizard dengan KMM template

  1. Click Next

Option 2: Menggunakan Kotlin Multiplatform Wizard Website

Visit kmp.jetbrains.com (opens in a new tab) dan follow wizard online.

KMM wizard website interface

Langkah 8: Configure Project

Di project configuration screen:

KMM project configuration form

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.

Android Studio menampilkan progress project creation

Setelah selesai, explore project structure:

Android Studio project navigator menampilkan KMM 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.kts

Key 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:

Android Studio editor menampilkan 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(): Platform

Penjelasan 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()

Side-by-side comparison Android dan iOS implementations

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:

Android Studio menampilkan 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:

Xcode menampilkan 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

Editor menampilkan updated Greeting.kt

Save file (Cmd/Ctrl + S).

Bagian 3: Running Android App

Langkah 15: Build Shared Module

Sebelum run apps, build shared module:

./gradlew :shared:build

Atau di Android Studio: Build > Make Project (Cmd+F9 / Ctrl+F9)

Terminal menampilkan build process

Build process akan:

  1. Compile Kotlin code untuk Android (JVM)
  2. Compile Kotlin code untuk iOS (Native)
  3. Generate iOS framework
  4. Package artifacts

Langkah 16: Start Android Emulator

Launch Android emulator seperti di tutorial Android Studio sebelumnya.

Android emulator running

Atau via command line:

emulator -list-avds
emulator -avd Pixel_6_API_33

Langkah 17: Run Android App

Di Android Studio:

  1. Select androidApp configuration dari dropdown
  2. Select emulator atau device
  3. Click Run button (▶) atau press Shift+F10

Android Studio toolbar dengan run configuration

Atau via command line:

./gradlew :androidApp:installDebug

Build akan:

  1. Compile shared Kotlin module
  2. Build Android app
  3. Install ke emulator/device
  4. Launch app

Langkah 18: App Running di Android

Aplikasi akan launch di Android emulator.

KMM Hello World app running di Android

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.TextAlign

Hot reload atau rebuild app untuk melihat perubahan.

Android app dengan improved UI

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.xcodeproj

Atau di Android Studio, right-click folder iosApp dan pilih Open In > Xcode.

Xcode project navigator menampilkan iOS project

Langkah 21: Configure iOS Project Signing

Di Xcode:

  1. Select project "iosApp" di navigator
  2. Select target "iosApp"
  3. Go to Signing & Capabilities tab
  4. Check Automatically manage signing
  5. Select your Team (Apple ID)

Xcode signing configuration

Xcode akan automatically generate provisioning profile.

Langkah 22: Build Shared Framework untuk iOS

Sebelum run iOS app, pastikan shared framework ter-build:

./gradlew :shared:embedAndSignAppleFrameworkForXcode

Atau di Android Studio:

  1. Open Gradle tool window (View > Tool Windows > Gradle)
  2. Navigate ke shared > Tasks > build
  3. Run embedAndSignAppleFrameworkForXcode

Gradle tasks untuk iOS framework

Ini akan compile Kotlin code ke native iOS framework.

Langkah 23: Run iOS App di Simulator

Di Xcode:

  1. Select iOS Simulator dari scheme selector (misalnya iPhone 15)
  2. Click Run button (▶) atau press Cmd+R

Xcode toolbar dengan simulator selection

Xcode akan:

  1. Build iOS application
  2. Link dengan shared framework
  3. Launch simulator
  4. Install dan run app

Langkah 24: App Running di iOS

iOS Simulator akan launch dan menampilkan aplikasi.

KMM Hello World app running di iOS simulator

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()
    }
}

Xcode editor menampilkan updated ContentView

Build and run (Cmd+R) untuk melihat perubahan.

iOS app dengan improved UI

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)
        }
    }
}

Editor menampilkan UserRepository.kt

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
            )
        }
    }
}

Android app menampilkan user list dari shared logic

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()
    }
}

iOS app menampilkan user list dari shared logic

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()
}

Side by side Android dan iOS UUID implementations

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"
}

build.gradle.kts dengan Ktor dependencies

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 install

Check Podfile memiliki reference ke shared framework.

Issue 3: Kotlin/Native Compilation Failed

Error: Cannot compile for iOS target

Solusi:

  1. Check Xcode Command Line Tools installed:
xcode-select --install
  1. Verify KDoctor output:
kdoctor
  1. Clean Kotlin/Native cache:
rm -rf ~/.konan

Issue 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:clean

Check 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 impl

2. 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:test

4. 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

Learning Resources

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

Blogs & Tutorials

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:

  1. Gradual Adoption - Bisa integrate ke existing native apps step by step
  2. Native Performance - No bridge, direct interop
  3. Type Safety - Kotlin's strong typing across platforms
  4. Leverage Existing Skills - Android devs bisa contribute ke iOS logic
  5. 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!