ในปี 2026 การพัฒนา App สำหรับหลาย Platform พร้อมกันกลายเป็นความจำเป็น ลูกค้าต้องการ App ทั้ง Android, iOS, Web และ Desktop แต่การเขียน Code แยกทุก Platform เป็นเรื่องที่สิ้นเปลืองทรัพยากรมหาศาล Kotlin Multiplatform (KMP) คือทางออกที่ JetBrains นำเสนอ โดยให้นักพัฒนาสามารถ Share Business Logic ข้ามทุก Platform ได้อย่างแท้จริง โดยไม่ต้องเสียสละ Native Performance หรือ Native UI ของแต่ละ Platform
บทความนี้จะพาคุณเรียนรู้ Kotlin Multiplatform ตั้งแต่แนวคิดพื้นฐาน ไปจนถึงการสร้างโปรเจกต์จริง พร้อมเปรียบเทียบกับ Flutter และ React Native อย่างละเอียด เหมาะสำหรับทั้งนักพัฒนา Android ที่อยากขยาย Skill และนักพัฒนาที่กำลังมองหา Cross-Platform Solution ที่ดีที่สุดในปี 2026
Kotlin Multiplatform (KMP) คืออะไร?
Kotlin Multiplatform (KMP) คือเทคโนโลยีจาก JetBrains ที่อนุญาตให้คุณเขียน Business Logic เพียงครั้งเดียวด้วยภาษา Kotlin แล้วนำไปใช้ร่วมกันบน Android, iOS, Web, Desktop และ Server ได้ทันที สิ่งที่ทำให้ KMP แตกต่างจาก Cross-Platform Framework อื่นๆ คือมันไม่ได้พยายาม Abstract ทุกอย่างออกจาก Platform แต่ให้คุณ Share เฉพาะส่วนที่ควร Share (เช่น Networking, Data Layer, Business Logic) และเขียน UI แบบ Native ตามแต่ละ Platform ได้
JetBrains ประกาศให้ KMP เป็น Stable ตั้งแต่ Kotlin 1.9.20 และในปี 2026 ด้วย Kotlin 2.1+ KMP ได้รับการพัฒนาจนมีความสมบูรณ์สูงมาก Google เองก็ประกาศ Official Support สำหรับ KMP ใน Android Development ทำให้ KMP ได้รับความเชื่อมั่นจากชุมชนนักพัฒนาทั่วโลก
หลักการทำงานของ KMP
KMP ใช้ Kotlin Compiler ที่สามารถ Compile Code ไปเป็น Target ต่างๆ ได้:
- Kotlin/JVM — สำหรับ Android และ Server-side Java
- Kotlin/Native — สำหรับ iOS, macOS, Linux, Windows (ใช้ LLVM Compiler)
- Kotlin/JS — สำหรับ Web Browser (Compile เป็น JavaScript)
- Kotlin/Wasm — สำหรับ WebAssembly (ใหม่ ประสิทธิภาพสูง)
KMP vs Flutter vs React Native — เปรียบเทียบ Cross-Platform 2026
ก่อนที่จะลงลึกใน KMP เรามาเปรียบเทียบกับ Flutter และ React Native ซึ่งเป็น Cross-Platform Framework ยอดนิยมอีกสองตัว
| Feature | KMP | Flutter | React Native |
|---|---|---|---|
| ภาษา | Kotlin | Dart | JavaScript/TypeScript |
| UI Approach | Native UI / Compose Multiplatform | Custom Rendering Engine | Bridge to Native UI |
| Code Sharing | Business Logic + optional UI | ทุกอย่างรวม UI | ส่วนใหญ่รวม UI |
| Performance | Native-level | Near-native | Good (New Architecture) |
| iOS Integration | ดีมาก (Swift interop) | ปานกลาง | ดี (Native Modules) |
| Learning Curve | ง่ายสำหรับ Android Dev | ต้องเรียน Dart | ง่ายสำหรับ Web Dev |
| Web Support | Kotlin/JS, Kotlin/Wasm | Flutter Web | React Native Web |
| Desktop Support | Compose Multiplatform | Flutter Desktop | จำกัด |
| Backed by | JetBrains + Google | Meta | |
| Maturity (2026) | Stable, เติบโตเร็ว | Mature | Mature |
Kotlin Basics สำหรับคนที่ยังไม่รู้จัก Kotlin
ก่อนจะเริ่ม KMP มาทบทวน Kotlin Syntax พื้นฐานกันก่อน Kotlin เป็นภาษาที่สั้นกระชับ Type-safe และ Null-safe ออกแบบโดย JetBrains เป็นภาษาที่ Java Developer จะคุ้นเคยทันที
// Variables
val name: String = "KMP" // Immutable (val = final)
var count: Int = 0 // Mutable
// Null Safety - จุดเด่นของ Kotlin
val nullableName: String? = null
val length = nullableName?.length ?: 0 // Elvis operator
// Data Classes
data class User(
val id: Int,
val name: String,
val email: String
)
// Functions
fun greet(name: String): String = "Hello, $name!"
// Extension Functions
fun String.addExclamation(): String = "$this!"
// Higher-order Functions
val numbers = listOf(1, 2, 3, 4, 5)
val doubled = numbers.map { it * 2 }
val evens = numbers.filter { it % 2 == 0 }
// Coroutines (async/await)
suspend fun fetchUser(id: Int): User {
return apiService.getUser(id) // suspend function
}
// Sealed Classes
sealed class Result<out T> {
data class Success<T>(val data: T) : Result<T>()
data class Error(val message: String) : Result<Nothing>()
object Loading : Result<Nothing>()
}
โครงสร้าง KMP Project
KMP Project มีโครงสร้างหลักแบ่งเป็น 3 ส่วน: Shared Module (Business Logic ที่ใช้ร่วมกัน), Android App และ iOS App
my-kmp-project/
├── shared/ # Shared Kotlin Code
│ ├── src/
│ │ ├── commonMain/ # Code ที่ใช้ทุก Platform
│ │ │ └── kotlin/
│ │ │ ├── data/
│ │ │ │ ├── repository/
│ │ │ │ └── model/
│ │ │ ├── domain/
│ │ │ │ └── usecase/
│ │ │ ├── network/
│ │ │ │ └── ApiService.kt
│ │ │ └── Platform.kt
│ │ ├── commonTest/ # Shared Tests
│ │ ├── androidMain/ # Android-specific code
│ │ │ └── kotlin/
│ │ │ └── Platform.android.kt
│ │ ├── iosMain/ # iOS-specific code
│ │ │ └── kotlin/
│ │ │ └── Platform.ios.kt
│ │ ├── jsMain/ # Web-specific code
│ │ └── desktopMain/ # Desktop-specific code
│ └── build.gradle.kts
├── androidApp/ # Android Application
│ ├── src/main/
│ │ ├── java/
│ │ └── res/
│ └── build.gradle.kts
├── iosApp/ # iOS Application (Xcode Project)
│ ├── iosApp/
│ │ ├── ContentView.swift
│ │ └── iOSApp.swift
│ └── iosApp.xcodeproj
├── build.gradle.kts # Root build file
└── settings.gradle.kts
ตั้งค่า build.gradle.kts สำหรับ Shared Module
// shared/build.gradle.kts
plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.androidLibrary)
alias(libs.plugins.kotlinSerialization)
}
kotlin {
// Android Target
androidTarget {
compilations.all {
compileTaskProvider.configure {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_17)
}
}
}
}
// iOS Targets
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "Shared"
isStatic = true
}
}
// Desktop Target
jvm("desktop")
// Web Target
js(IR) {
browser()
}
sourceSets {
commonMain.dependencies {
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.ktor.serialization.kotlinx.json)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.serialization.json)
implementation(libs.sqldelight.runtime)
implementation(libs.koin.core)
}
androidMain.dependencies {
implementation(libs.ktor.client.android)
implementation(libs.sqldelight.android.driver)
implementation(libs.koin.android)
}
iosMain.dependencies {
implementation(libs.ktor.client.darwin)
implementation(libs.sqldelight.native.driver)
}
commonTest.dependencies {
implementation(libs.kotlin.test)
implementation(libs.kotlinx.coroutines.test)
}
}
}
expect/actual — หัวใจของ KMP
กลไก expect/actual คือวิธีที่ KMP จัดการกับ Platform-specific Code คุณประกาศ expect ใน Common Code เพื่อบอกว่า "ฉันต้องการสิ่งนี้" แล้วแต่ละ Platform จะ Implement actual ตามความเหมาะสม
// commonMain/kotlin/Platform.kt
expect class Platform() {
val name: String
val version: String
}
expect fun getPlatformName(): String
// androidMain/kotlin/Platform.android.kt
actual class Platform actual constructor() {
actual val name: String = "Android"
actual val version: String = "${android.os.Build.VERSION.SDK_INT}"
}
actual fun getPlatformName(): String = "Android ${android.os.Build.VERSION.SDK_INT}"
// iosMain/kotlin/Platform.ios.kt
import platform.UIKit.UIDevice
actual class Platform actual constructor() {
actual val name: String = "iOS"
actual val version: String = UIDevice.currentDevice.systemVersion
}
actual fun getPlatformName(): String = "iOS ${UIDevice.currentDevice.systemVersion}"
// desktopMain/kotlin/Platform.desktop.kt
actual class Platform actual constructor() {
actual val name: String = "Desktop"
actual val version: String = System.getProperty("os.version") ?: "Unknown"
}
actual fun getPlatformName(): String = "Desktop JVM"
expect declaration ต้องมี actual implementation ใน ทุก target platform ที่กำหนดไว้ ถ้า Target มี Android + iOS + Desktop ต้องมี actual ทั้ง 3 ที่ ไม่งั้น Compile ไม่ผ่าน
KMP สำหรับ Mobile — Compose Multiplatform
Compose Multiplatform คือ Declarative UI Framework จาก JetBrains ที่ทำให้ Jetpack Compose (Android) สามารถทำงานได้บน iOS, Desktop และ Web ได้ด้วย ทำให้คุณสามารถ Share ทั้ง Business Logic และ UI Code ข้าม Platform ได้เหมือน Flutter แต่ด้วย Kotlin
// Shared Compose UI - ใช้ได้ทุก Platform
@Composable
fun UserListScreen(viewModel: UserViewModel) {
val users by viewModel.users.collectAsState()
val isLoading by viewModel.isLoading.collectAsState()
Column(
modifier = Modifier.fillMaxSize().padding(16.dp)
) {
Text(
text = "Users",
style = MaterialTheme.typography.headlineMedium,
modifier = Modifier.padding(bottom = 16.dp)
)
if (isLoading) {
CircularProgressIndicator(
modifier = Modifier.align(Alignment.CenterHorizontally)
)
}
LazyColumn {
items(users) { user ->
UserCard(user = user)
}
}
}
}
@Composable
fun UserCard(user: User) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 4.dp),
elevation = CardDefaults.cardElevation(2.dp)
) {
Row(
modifier = Modifier.padding(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
AsyncImage(
model = user.avatarUrl,
contentDescription = user.name,
modifier = Modifier.size(48.dp).clip(CircleShape)
)
Spacer(Modifier.width(12.dp))
Column {
Text(user.name, style = MaterialTheme.typography.bodyLarge)
Text(user.email, style = MaterialTheme.typography.bodySmall)
}
}
}
}
Compose Multiplatform บน iOS
บน iOS Compose Multiplatform จะ Render ผ่าน Skia Engine (เหมือน Flutter) ซึ่งให้ Pixel-perfect UI ข้าม Platform แต่คุณก็สามารถผสม Native SwiftUI Component ได้ตามต้องการ
// iOS Entry Point - iosApp/ContentView.swift
import SwiftUI
import Shared
struct ComposeView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIViewController {
MainViewControllerKt.MainViewController()
}
func updateUIViewController(_ uiViewController: UIViewController,
context: Context) {}
}
struct ContentView: View {
var body: some View {
ComposeView()
.ignoresSafeArea(.keyboard)
}
}
KMP + SwiftUI สำหรับ iOS
ถ้าคุณต้องการ Native Look & Feel สูงสุดบน iOS คุณสามารถเลือกใช้ SwiftUI สำหรับ UI Layer และใช้ KMP Shared Module เฉพาะ Business Logic ได้ วิธีนี้เป็นที่นิยมมากเพราะ iOS Developer ยังคงเขียน UI ด้วยเครื่องมือที่คุ้นเคย
// iosApp/UserListView.swift
import SwiftUI
import Shared // KMP Shared Framework
struct UserListView: View {
@StateObject private var viewModel = IOSUserViewModel()
var body: some View {
NavigationStack {
List(viewModel.users, id: \.id) { user in
HStack {
AsyncImage(url: URL(string: user.avatarUrl))
.frame(width: 44, height: 44)
.clipShape(Circle())
VStack(alignment: .leading) {
Text(user.name).font(.headline)
Text(user.email).font(.caption).foregroundStyle(.secondary)
}
}
}
.navigationTitle("Users")
.task { await viewModel.loadUsers() }
}
}
}
// Bridge KMP ViewModel to SwiftUI
class IOSUserViewModel: ObservableObject {
@Published var users: [User] = []
private let repository = UserRepository() // KMP Shared Class
func loadUsers() async {
do {
let result = try await repository.getUsers()
DispatchQueue.main.async {
self.users = result
}
} catch {
print("Error: \(error)")
}
}
}
KMP สำหรับ Web — Kotlin/JS และ Kotlin/Wasm
KMP ไม่ได้จำกัดเฉพาะ Mobile เท่านั้น คุณสามารถนำ Shared Code ไปใช้บน Web ได้ผ่าน Kotlin/JS (Compile เป็น JavaScript) หรือ Kotlin/Wasm (Compile เป็น WebAssembly) ซึ่งทั้งสองวิธีมีข้อดีแตกต่างกัน
// Kotlin/JS — ใช้ Shared Code ใน Web App
// build.gradle.kts
kotlin {
js(IR) {
browser {
commonWebpackConfig {
cssSupport { enabled.set(true) }
}
}
binaries.executable()
}
}
// jsMain/kotlin/Main.kt
import kotlinx.browser.document
import kotlinx.browser.window
fun main() {
val repository = UserRepository() // KMP Shared Code!
window.onload = {
document.getElementById("app")?.innerHTML = renderApp()
}
}
// Kotlin/Wasm — New in 2026, High Performance
kotlin {
wasmJs {
browser()
binaries.executable()
}
}
KMP สำหรับ Desktop
ด้วย Compose Multiplatform คุณสามารถสร้าง Desktop Application สำหรับ Windows, macOS และ Linux ได้อย่างง่ายดาย โดยใช้ Code Base เดียวกับ Mobile
// desktopMain/kotlin/Main.kt
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
fun main() = application {
Window(
onCloseRequest = ::exitApplication,
title = "KMP Desktop App"
) {
App() // Same Composable as Mobile!
}
}
// Shared App Composable
@Composable
fun App() {
MaterialTheme {
val viewModel = remember { UserViewModel() }
UserListScreen(viewModel = viewModel)
}
}
Ktor — Shared HTTP Client ข้ามทุก Platform
Ktor เป็น HTTP Client/Server Framework จาก JetBrains ที่ออกแบบมาเพื่อ KMP โดยเฉพาะ คุณเขียน Networking Code ครั้งเดียวแล้วใช้ได้ทุก Platform โดยแต่ละ Platform จะใช้ Engine ที่เหมาะสม (OkHttp บน Android, URLSession บน iOS เป็นต้น) คล้ายกับแนวคิด REST API Design ที่เราเคยพูดถึง
// commonMain/kotlin/network/ApiService.kt
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
prettyPrint = true
isLenient = true
})
}
}
suspend fun getUsers(): List<User> {
return client.get("https://api.example.com/users").body()
}
suspend fun getUserById(id: Int): User {
return client.get("https://api.example.com/users/$id").body()
}
suspend fun createUser(user: CreateUserRequest): User {
return client.post("https://api.example.com/users") {
contentType(ContentType.Application.Json)
setBody(user)
}.body()
}
}
// Data Models — Shared across all platforms
@Serializable
data class User(
val id: Int,
val name: String,
val email: String,
val avatarUrl: String
)
@Serializable
data class CreateUserRequest(
val name: String,
val email: String
)
Platform-specific HTTP Engine
// androidMain — ใช้ OkHttp
actual fun createHttpClient(): HttpClient = HttpClient(OkHttp)
// iosMain — ใช้ Darwin (URLSession)
actual fun createHttpClient(): HttpClient = HttpClient(Darwin)
// desktopMain — ใช้ CIO
actual fun createHttpClient(): HttpClient = HttpClient(CIO)
SQLDelight — Shared Database ข้ามทุก Platform
SQLDelight จาก Square (ผู้สร้าง Cash App) เป็น Database Library ที่ออกแบบมาเพื่อ KMP ทำงานคล้ายกับ Room บน Android แต่ใช้ได้ทุก Platform คุณเขียน SQL Schema ครั้งเดียว แล้ว SQLDelight จะ Generate Type-safe Kotlin Code ให้อัตโนมัติ เปรียบเทียบได้กับ Prisma ORM ในโลก JavaScript
-- shared/src/commonMain/sqldelight/com/example/db/User.sq
-- สร้างตาราง
CREATE TABLE UserEntity (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL,
avatar_url TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- Query
selectAll:
SELECT * FROM UserEntity ORDER BY created_at DESC;
selectById:
SELECT * FROM UserEntity WHERE id = :id;
insert:
INSERT INTO UserEntity(name, email, avatar_url)
VALUES (:name, :email, :avatarUrl);
deleteById:
DELETE FROM UserEntity WHERE id = :id;
searchByName:
SELECT * FROM UserEntity WHERE name LIKE '%' || :query || '%';
// ใช้งาน SQLDelight ใน Shared Code
class LocalDatabase(driverFactory: DatabaseDriverFactory) {
private val database = AppDatabase(driverFactory.createDriver())
private val queries = database.userEntityQueries
fun getAllUsers(): List<UserEntity> {
return queries.selectAll().executeAsList()
}
fun getUserById(id: Long): UserEntity? {
return queries.selectById(id).executeAsOneOrNull()
}
fun insertUser(name: String, email: String, avatarUrl: String) {
queries.insert(name, email, avatarUrl)
}
fun deleteUser(id: Long) {
queries.deleteById(id)
}
}
// expect/actual สำหรับ Database Driver
expect class DatabaseDriverFactory {
fun createDriver(): SqlDriver
}
// androidMain
actual class DatabaseDriverFactory(private val context: Context) {
actual fun createDriver(): SqlDriver {
return AndroidSqliteDriver(AppDatabase.Schema, context, "app.db")
}
}
// iosMain
actual class DatabaseDriverFactory {
actual fun createDriver(): SqlDriver {
return NativeSqliteDriver(AppDatabase.Schema, "app.db")
}
}
Koin — Dependency Injection สำหรับ KMP
Koin เป็น Lightweight DI Framework ที่รองรับ KMP อย่างสมบูรณ์ ใช้ง่ายกว่า Dagger/Hilt มากเพราะไม่ต้อง Annotation Processing เหมาะสำหรับโปรเจกต์ KMP ที่ต้องจัดการ Dependency ข้ามหลาย Platform เป็นส่วนหนึ่งของ Design Patterns ที่ดีในการพัฒนา Software
// commonMain/kotlin/di/SharedModule.kt
import org.koin.dsl.module
val sharedModule = module {
single { ApiService() }
single { UserRepository(get(), get()) }
factory { GetUsersUseCase(get()) }
}
// androidMain/kotlin/di/AndroidModule.kt
val androidModule = module {
single { DatabaseDriverFactory(get()) }
single { LocalDatabase(get()) }
}
// iosMain/kotlin/di/IosModule.kt
val iosModule = module {
single { DatabaseDriverFactory() }
single { LocalDatabase(get()) }
}
// KMP App Initialization
fun initKoin() {
startKoin {
modules(sharedModule, platformModule())
}
}
// expect/actual for platform module
expect fun platformModule(): Module
Testing Shared Code ใน KMP
หนึ่งในข้อดีที่สำคัญที่สุดของ KMP คือคุณเขียน Test ครั้งเดียวสำหรับ Shared Code แล้ว Test นั้นจะทำงานบนทุก Platform ที่ Support ทำให้มั่นใจว่า Business Logic ทำงานถูกต้องบนทุก Platform โดยใช้แนวคิดจาก Software Testing ที่ดี
// commonTest/kotlin/UserRepositoryTest.kt
import kotlin.test.*
import kotlinx.coroutines.test.runTest
class UserRepositoryTest {
private lateinit var repository: UserRepository
private lateinit var fakeApi: FakeApiService
private lateinit var fakeDb: FakeLocalDatabase
@BeforeTest
fun setup() {
fakeApi = FakeApiService()
fakeDb = FakeLocalDatabase()
repository = UserRepository(fakeApi, fakeDb)
}
@Test
fun `getUsers returns cached data when available`() = runTest {
// Given
fakeDb.insertUser("John", "john@test.com", "")
// When
val result = repository.getUsers(forceRefresh = false)
// Then
assertEquals(1, result.size)
assertEquals("John", result.first().name)
}
@Test
fun `getUsers fetches from API when cache is empty`() = runTest {
// Given
fakeApi.users = listOf(
User(1, "Jane", "jane@test.com", "")
)
// When
val result = repository.getUsers(forceRefresh = false)
// Then
assertEquals(1, result.size)
assertEquals("Jane", result.first().name)
assertTrue(fakeApi.fetchCalled)
}
@Test
fun `getUsers forces API refresh when requested`() = runTest {
// Given
fakeDb.insertUser("Old", "old@test.com", "")
fakeApi.users = listOf(User(1, "New", "new@test.com", ""))
// When
val result = repository.getUsers(forceRefresh = true)
// Then
assertTrue(fakeApi.fetchCalled)
assertEquals("New", result.first().name)
}
}
KMP ใน Production — บริษัทที่ใช้งานจริง
KMP ไม่ใช่แค่เทคโนโลยีทดลอง แต่ถูกใช้ใน Production โดยบริษัทระดับโลกหลายแห่ง:
| บริษัท | การใช้งาน KMP | ผลลัพธ์ |
|---|---|---|
| Netflix | Prodicle App — Share Business Logic ระหว่าง Android/iOS สำหรับทีม Production | ลดเวลาพัฒนา Feature ใหม่ 50% |
| Cash App (Square) | ใช้ KMP Share Networking, Data Layer, Business Logic ระหว่าง Android/iOS | Code Sharing 60%+ ลด Bug ข้าม Platform |
| Philips | Health App Share Medical Logic ข้ามทุก Platform ด้วย KMP | ลดทีม Dev ที่ต้องการ รับประกันความถูกต้องเท่ากันทุก Platform |
| VMware | Workspace ONE SDK ใช้ KMP สำหรับ Share Code ข้าม Mobile Platform | Maintain SDK เดียวแทนที่จะเป็นสอง Codebase |
| Touchlab | Consultancy ที่เชี่ยวชาญ KMP ช่วยหลายบริษัทย้ายมา KMP | สร้าง SKIE Library ช่วย Swift Interop |
| Forbes | Forbes Mobile App ใช้ KMP Share Content Layer | เร่ง Feature Parity ระหว่าง Android/iOS |
KMP vs Compose Multiplatform — ต่างกันอย่างไร?
หลายคนสับสนระหว่าง KMP กับ Compose Multiplatform เพราะชื่อคล้ายกัน แต่จริงๆ แล้วต่างกันชัดเจน:
- KMP (Kotlin Multiplatform) — เทคโนโลยีสำหรับ Share Business Logic (Non-UI Code) ข้าม Platform ใช้ Native UI ของแต่ละ Platform (XML/Compose บน Android, SwiftUI/UIKit บน iOS)
- Compose Multiplatform — UI Framework ที่ทำให้ Jetpack Compose ทำงานข้าม Platform ได้ ใช้ร่วมกับ KMP เพื่อ Share ทั้ง UI และ Logic
กล่าวง่ายๆ คือ KMP คือ Foundation และ Compose Multiplatform คือ UI Layer ที่เสริมด้านบน คุณสามารถใช้ KMP โดยไม่ใช้ Compose Multiplatform ได้ (เขียน Native UI แทน) แต่ไม่สามารถใช้ Compose Multiplatform โดยไม่มี KMP ได้
ข้อจำกัดและข้อควรพิจารณา
แม้ KMP จะมีข้อดีมากมาย แต่ก็ยังมีข้อจำกัดที่ควรรู้ก่อนตัดสินใจใช้งาน:
- iOS Build Time — Kotlin/Native สำหรับ iOS ยังใช้เวลา Compile นานกว่า Swift โดยเฉพาะ Debug Build แต่ JetBrains พัฒนาปรับปรุงอย่างต่อเนื่อง
- iOS Debugging — การ Debug Kotlin Code บน iOS ยังไม่สมบูรณ์เท่า Native Swift Debugging แต่ Fleet IDE และ Android Studio มี Plugin ช่วยแล้ว
- Library Ecosystem — Library บางตัวยังไม่รองรับ KMP ต้องใช้ expect/actual wrapper หรือหา Alternative ที่รองรับ
- Team Skill — ทีม iOS Developer ต้องเรียน Kotlin เพิ่ม (แม้ Syntax จะคล้าย Swift ก็ตาม)
- Binary Size — Kotlin/Native Framework สำหรับ iOS อาจมีขนาดใหญ่กว่า Pure Swift ประมาณ 5-10 MB
- Compose Multiplatform Maturity — Compose Multiplatform บน iOS ยังอยู่ในช่วงพัฒนาเร็ว มี Breaking Changes ได้
- Concurrency Model — Kotlin/Native เคยมี Memory Model ที่ต่างจาก JVM แต่ New Memory Model แก้ปัญหานี้แล้ว
Migration จาก Native สู่ KMP — Step-by-Step
ถ้าคุณมี App Native อยู่แล้ว (Android + iOS แยกกัน) การ Migrate มา KMP ไม่จำเป็นต้องทำทีเดียว สามารถทำทีละส่วนได้:
Phase 1: เริ่มจาก Data Models
// ย้าย Data Models มา commonMain
@Serializable
data class Product(
val id: String,
val name: String,
val price: Double,
val category: String,
val imageUrl: String
)
// ทั้ง Android และ iOS ใช้ Model เดียวกัน
// ลดโอกาสที่ Data จะไม่ตรงกัน
Phase 2: ย้าย Networking Layer
// ย้าย API Service มา commonMain
class ProductApi(private val client: HttpClient) {
suspend fun getProducts(): List<Product> {
return client.get("/api/products").body()
}
}
// Android และ iOS เรียกใช้ ProductApi ตัวเดียวกัน
Phase 3: ย้าย Business Logic
// Repository Pattern ใน commonMain
class ProductRepository(
private val api: ProductApi,
private val db: LocalDatabase
) {
suspend fun getProducts(forceRefresh: Boolean = false): List<Product> {
if (!forceRefresh) {
val cached = db.getProducts()
if (cached.isNotEmpty()) return cached
}
val products = api.getProducts()
db.saveProducts(products)
return products
}
suspend fun searchProducts(query: String): List<Product> {
return db.searchProducts(query)
}
}
Phase 4: พิจารณา Shared UI (optional)
ขั้นตอนนี้เป็น Optional คุณสามารถเลือก Share UI ด้วย Compose Multiplatform หรือยังคงใช้ Native UI ก็ได้ การตัดสินใจขึ้นอยู่กับทีมและความต้องการของโปรเจกต์
KMP Ecosystem ที่ควรรู้จัก
| Library | หน้าที่ | Platform Support |
|---|---|---|
| Ktor | HTTP Client/Server | All Platforms |
| SQLDelight | Type-safe SQL Database | All Platforms |
| Koin | Dependency Injection | All Platforms |
| Kotlinx.serialization | JSON/CBOR Serialization | All Platforms |
| Kotlinx.coroutines | Async/Concurrency | All Platforms |
| Kotlinx.datetime | Date/Time utilities | All Platforms |
| Compose Multiplatform | Declarative UI | Android, iOS, Desktop, Web |
| Multiplatform Settings | SharedPreferences/UserDefaults | All Platforms |
| SKIE | Better Swift Interop | iOS |
| KMM-ViewModel | Shared ViewModel | Android, iOS |
| Napier | Logging | All Platforms |
| Kamel | Image Loading for Compose | All Compose Platforms |
สร้างโปรเจกต์ KMP แรก — Quick Start
วิธีที่ง่ายที่สุดในการเริ่ม KMP คือใช้ KMP Wizard จาก JetBrains:
- ไปที่
kmp.jetbrains.com - เลือก Platform ที่ต้องการ (Android + iOS + Desktop + Web)
- เลือก Libraries ที่ต้องการ (Ktor, SQLDelight, Koin)
- Generate Project แล้ว Download
- เปิดด้วย Android Studio หรือ Fleet
# หรือใช้ Command Line
# ติดตั้ง KMP Plugin สำหรับ Android Studio
# File > New > New Project > Kotlin Multiplatform
# Build and Run
./gradlew :shared:build # Build Shared Module
./gradlew :androidApp:installDebug # Run Android App
./gradlew :desktopApp:run # Run Desktop App
# iOS — ต้องใช้ Xcode บน macOS
# เปิด iosApp/iosApp.xcodeproj แล้ว Run ใน Xcode
สรุป — KMP คือ Future ของ Cross-Platform Development
Kotlin Multiplatform (KMP) กำลังเปลี่ยนวิธีที่นักพัฒนาคิดเกี่ยวกับ Cross-Platform Development แทนที่จะเลือกระหว่าง "Native Performance" กับ "Code Sharing" KMP ให้คุณได้ทั้งสองอย่าง คุณ Share Business Logic ที่ไม่เปลี่ยนตาม Platform (Networking, Database, Validation, Business Rules) และเขียน UI ที่ดีที่สุดสำหรับแต่ละ Platform
ในปี 2026 ด้วย Compose Multiplatform ที่เติบโตอย่างรวดเร็ว, Google Official Support, และ Ecosystem ที่ครบเครื่อง (Ktor, SQLDelight, Koin) KMP กลายเป็นตัวเลือก Cross-Platform ที่น่าจับตามองที่สุด ไม่ว่าคุณจะเป็น Android Developer ที่อยากขยายไป iOS, หรือ Startup ที่ต้องการ Launch ทุก Platform พร้อมกัน KMP คือเทคโนโลยีที่ควรลงทุนเรียนรู้อย่างจริงจัง
อ่านบทความเกี่ยวข้อง: Flutter Guide | React Native Guide | Mobile Architecture | Java/Spring Boot | Mobile Performance
