2026๋ Kotlin Multiplatform: ์๋๋ก์ด๋์ iOS ์ฝ๋ ๊ณต์
2026๋ Kotlin Multiplatform์ด Android์ iOS์์ ๋น์ฆ๋์ค ๋ก์ง์ ๊ณต์ ํ๋ ๋ฐฉ๋ฒ์ ์ค๋ช ํฉ๋๋ค. Gradle ์ค์ , expect/actual, Ktor, Compose Multiplatform, KMP ๋ฉด์ ์ง๋ฌธ๊น์ง ๋ค๋ฃน๋๋ค.

Kotlin Multiplatform(KMP)์ ํ๋์ Kotlin ์ฝ๋๋ฒ ์ด์ค๋ก Android์ iOS ์ฑ์ ๋น์ฆ๋์ค ๋ก์ง์ ํจ๊ป ๊ตฌ๋ํ๋ฉด์๋, ๊ฐ ํ๋ซํผ์ด ์์ ํ ๋ค์ดํฐ๋ธ UI์ ์ฑ๋ฅ, ๊ทธ๋ฆฌ๊ณ ์์ฒด SDK ์ ๊ทผ์ ๊ทธ๋๋ก ์ ์งํ๊ฒ ํด ์ค๋๋ค. 2026๋ ์ KMP๋ ๋ ์ด์ ์คํ์ด ์๋๋๋ค. ์์ ๋ฒ์ ์ด๋ฉฐ Google์ด ๊ณต์์ ์ผ๋ก ์ง์ํ๊ณ , Netflix, McDonald's, Forbes, Cash App์ ํ๋ก๋์ ํ๊ฒฝ์์ ์ค์ ๋ก ๋์ํ๊ณ ์์ต๋๋ค. ์ด ๊ธ์์๋ ์ฝ๋ ๊ณต์ ๊ฐ ์ค์ ๋ก ์ด๋ป๊ฒ ์๋ํ๋์ง, ๊ณต์ ๋ชจ๋์ ์ด๋ป๊ฒ ๊ตฌ์ฑํ๋์ง, ๊ทธ๋ฆฌ๊ณ KMP ๋ฉด์ ์ ์์ ์ดํดํด ๋ ๋งํ ํธ๋ ์ด๋์คํ๋ฅผ ๊น์ด ์๊ฒ ๋ค๋ฃน๋๋ค.
Kotlin Multiplatform์ด ๊ณต์ ํ๋ ๊ฒ์ ์ปดํ์ผ๋ ๋ก์ง์ด์ง ๋ฐํ์์ด ์๋๋๋ค. ๊ณตํต Kotlin์ Android์ฉ์ผ๋ก๋ JVM ๋ฐ์ดํธ์ฝ๋๋ก, iOS์ฉ์ผ๋ก๋ (LLVM์ ํตํด) ๋ค์ดํฐ๋ธ ๋ฐ์ด๋๋ฆฌ๋ก ์ปดํ์ผ๋ฉ๋๋ค. JavaScript ๋ธ๋ฆฌ์ง๋, ๋ด์ฅ ์น๋ทฐ๋, ๋ฆฌํ๋ ์ ๊ณ์ธต๋ ์๊ธฐ ๋๋ฌธ์ ๊ณต์ ์ฝ๋๋ ์์ชฝ ํ๋ซํผ์์ ๋ค์ดํฐ๋ธ ์๋๋ก ์คํ๋ฉ๋๋ค.
Kotlin Multiplatform์ด ๋ค์ดํฐ๋ธ ์ฑ๋ฅ์ ํฌ์ํ์ง ์๊ณ ์ฝ๋๋ฅผ ๊ณต์ ํ๋ ๋ฐฉ์
ํต์ฌ ๋ฉ์ปค๋์ฆ์ ์์ค ์ธํธ์ ๊ณ์ธต ๊ตฌ์กฐ์
๋๋ค. commonMain์๋ ๋คํธ์ํน, ์ง๋ ฌํ, ๋น์ฆ๋์ค ๊ท์น, ๋ทฐ ๋ชจ๋ธ์ฒ๋ผ ํ๋ซํผ์ ์ข
์๋์ง ์๋ Kotlin์ ๋ก๋๋ค. androidMain๊ณผ iosMain ๊ฐ์ ํ๋ซํผ ์์ค ์ธํธ์๋ ํ๋ซํผ API๋ฅผ ๋ค๋ฃจ๋ ์ฝ๋๋ฅผ ๋ก๋๋ค. ์ปดํ์ผ๋ฌ๋ Android์ฉ์ผ๋ก commonMain๊ณผ androidMain์์ JVM ์ํฐํฉํธ๋ฅผ, iOS์ฉ์ผ๋ก commonMain๊ณผ iosMain์์ ๋ค์ดํฐ๋ธ ํ๋ ์์ํฌ๋ฅผ ์์ฑํฉ๋๋ค.
2026๋ ์ Kotlin Multiplatform์ ๋จ์ผ ์ง์ค ๊ณต๊ธ์์์ ์ง์ ์ผ๋ก ์ด๋์ ๋ณด๋ ๊ฒ, ์ฆ ๋ชจ๋ธ, API ํด๋ผ์ด์ธํธ, ์บ์ฑ, ๊ฒ์ฆ์ ๊ณต์ ํ๋ ๋ฐ ๋ฌด๊ฒ๋ฅผ ๋ก๋๋ค. UI๋ Compose Multiplatform์ผ๋ก ๊ณต์ ํ ์๋ ์๊ณ , ํ๋ฉด ๋จ์๋ก SwiftUI๋ฅผ ์ฌ์ฉํด ์์ ํ ๋ค์ดํฐ๋ธ๋ก ๋จ๊ฒจ ๋ ์๋ ์์ต๋๋ค. "๋ก์ง์ ๊ณต์ ํ๊ณ UI๋ ์ ํํ๋ค"๋ ์ด ๋ชจ๋ธ์ด์ผ๋ง๋ก ๊ธฐ์กด ์ฑ์ ๋ค์ ์์ฑํ์ง ์๊ณ ๋ ํ์ด KMP๋ฅผ ๋์ ํ๋ ์ด์ ์ ๋๋ค.
Kotlin Multiplatform์ ํ๋์ ๊ณต์ ๋ชจ๋์ ์ฌ๋ฌ ํ๊น(JVM ์์ Android, ๋ค์ดํฐ๋ธ๋ก์์ iOS, ๊ทธ๋ฆฌ๊ณ ๋ฐ์คํฌํฑ๊ณผ ์น)์ผ๋ก ์ปดํ์ผํ๋ Kotlin ๊ธฐ์ ์ ๋๋ค. ๋๋ถ์ ๋น์ฆ๋์ค ๋ก์ง์ ํ ๋ฒ๋ง ์์ฑํ๋ฉด ๋๊ณ , ๊ฐ ํ๋ซํผ์ ๋ค์ดํฐ๋ธ UI์ ์์ ํ SDK ์ ๊ทผ์ ๊ทธ๋๋ก ์ ์งํฉ๋๋ค. ์ด์ Google์ ์ด๋ฅผ ์ผ๊ธ ์ต์ ์ผ๋ก ์ง์ํ๋ฉฐ, Room, DataStore, ViewModel, Paging ๊ฐ์ Jetpack ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ KMP ์ํฐํฉํธ๋ฅผ ์ ๊ณตํฉ๋๋ค.
๊ณต์ ๋ชจ๋์ ๋ฌด์์ ๋ฃ์์ง ๊ฒฐ์ ํ๋ ์ผ์ KMP ํ๋ก์ ํธ์์ ๊ฐ์ฅ ์ค์ํ ์ํคํ ์ฒ ํ๋จ์ ๋๋ค. ์๋ ํ๋ 2026๋ ์ ๋๋ค์ ํ๋ก๋์ ํ์ด ๊ฒฝ๊ณ๋ฅผ ์ด๋์ ๊ธ๋์ง๋ฅผ ๋ณด์ฌ ์ค๋๋ค. ํ๋ ์ ํ ์ด์ ๊ณ์ธต ์๋์ ๋ชจ๋ ๊ฒ์ ๊ณต์ ์ ์ ๋ ฅํ ํ๋ณด์ด๋ฉฐ, ํ๋ซํผ์ UX ๊ด๋ก์ ๋ฟ๋ ๊ฒ์ ๋๊ฐ ๋ค์ดํฐ๋ธ๋ก ๋จ์ต๋๋ค.
| ๊ณ์ธต | commonMain์์ ๊ณต์ ? | ์ด์ | |-------|---------------------|--------| | ๋ฐ์ดํฐ ๋ชจ๋ธ๊ณผ DTO | ์ | ์์ชฝ ํ๋ซํผ์์ ๋์ผํ API ๊ณ์ฝ | | ๋คํธ์ํน๊ณผ ์บ์ฑ | ์ | HTTP ์คํ ํ๋, ๋ฒ๊ทธ ํ๋ฉด ํ๋ | | ๋น์ฆ๋์ค ๊ท์น๊ณผ ๊ฒ์ฆ | ์ | ๋๋ฉ์ธ์ OS๋ง๋ค ๋ค๋ฅด์ง ์์ | | ๋ทฐ ๋ชจ๋ธ๊ณผ ์ํ | ๋๊ฐ | Compose์ SwiftUI ๋ชจ๋ ๊ณต์ ์ํ๋ฅผ ์๋น | | UI ๋ ๋๋ง | ์ ํ | Compose๋ก ๊ณต์ ํ๊ฑฐ๋ ํ๋ฉด๋ณ ๋ค์ดํฐ๋ธ | | ํ๋ซํผ API(์นด๋ฉ๋ผ, ์์ฒด ์ธ์ฆ) | ์๋์ค | ๋์ expect/actual๋ก ๋ ธ์ถ |
์ป๋ ์ด๋์ ์ฑ์ด ์ด ํ์ ์๋์ชฝ ์ ๋ฐ์ ์ผ๋ง๋ ์ฐจ์งํ๋๋์ ๋น๋กํด ์ปค์ง๋๋ค. UI๊ฐ ์๊ณ ๋ฐ์ดํฐ ์ค์ฌ์ธ ์ ํ์ผ์๋ก ๊ณต์ ๋์ด ๋ง๊ณ , ๊ณ ๋๋ก ๋ง์ถคํ๋๊ณ ์ ๋๋ฉ์ด์ ์ค์ฌ์ธ ์ฑ์ผ์๋ก ๊ณต์ ๋์ด ์ ์ต๋๋ค. ์ด๋ ์ชฝ ๊ทน๋จ๋ ํ๋ฆฐ ๊ฒ์ ์๋๋๋ค. ๊ทธ๋์ KMP๋ ์ ๋ถ ์๋๋ฉด ์ ๋ฌด ์์ ์ฌ์์ฑ๋ณด๋ค ์ ์ง์ ๋์ ์ ์ ๋ง์ต๋๋ค.
Gradle์์ ๊ณต์ ๋ชจ๋ ๊ตฌ์ฑํ๊ธฐ
KMP ๋ชจ๋์ Kotlin DSL๋ก ํ๊น๊ณผ ์์ค ์ธํธ๋ฅผ ์ ์ธํฉ๋๋ค. ๋ค์ build.gradle.kts๋ Android์ ์ธ ๊ฐ์ง iOS ์ํคํ
์ฒ(์ค๊ธฐ๊ธฐ, Intel ์๋ฎฌ๋ ์ดํฐ, Apple Silicon ์๋ฎฌ๋ ์ดํฐ)๋ฅผ ์ค์ ํ๊ณ , iOS ์ถ๋ ฅ์ Shared๋ผ๋ ์ด๋ฆ์ ํ๋ ์์ํฌ๋ก ๋
ธ์ถํฉ๋๋ค.
plugins {
kotlin("multiplatform")
kotlin("plugin.serialization")
id("com.android.library")
}
kotlin {
// Android target compiles commonMain + androidMain to JVM bytecode
androidTarget()
// Three iOS targets: device, Intel sim, Apple Silicon sim
listOf(iosArm64(), iosX64(), iosSimulatorArm64()).forEach { target ->
target.binaries.framework {
baseName = "Shared" // becomes "import Shared" in Swift
isStatic = true
}
}
sourceSets {
commonMain.dependencies {
implementation("io.ktor:ktor-client-core:3.3.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
}
androidMain.dependencies {
implementation("io.ktor:ktor-client-okhttp:3.3.0")
}
iosMain.dependencies {
implementation("io.ktor:ktor-client-darwin:3.3.0")
}
}
}๊ฐ ํ๊น์ ํ๋ซํผ๋ณ Ktor ์์ง(Android์์๋ okhttp, iOS์์๋ darwin)์ ๊ฐ์ ธ์ค๋ ๋ฐ๋ฉด, ๊ณต์ ์ฝ๋๋ ๊ณตํต ktor-client-core API์๋ง ์์กดํฉ๋๋ค. ์ค์ ๊ฐ๋ฅํ ์ต์
์ ์ฒด๋ Kotlin Multiplatform ๊ณต์ ๋ฌธ์์ ์ ๋ฆฌ๋์ด ์์ต๋๋ค.
expect์ actual๋ก ํ๋ซํผ๋ณ ์ฝ๋ ์์ฑํ๊ธฐ
์ผ๋ถ ๋ก์ง์ ํ๋ซํผ API๊ฐ ํ์ํ๊ธฐ ๋๋ฌธ์ commonMain์ ๋ ์ ์์ต๋๋ค. expect/actual ๋ฉ์ปค๋์ฆ์ ๊ณตํต ์ฝ๋์์ ํํ๋ฅผ ์ ์ธํ๊ณ ํ๊น๋ณ๋ก ๊ตฌ์ฒด์ ์ธ ๊ตฌํ์ ์ ๊ณตํ๋ฉฐ, ์ปดํ์ผ ์์ ์ ํด๊ฒฐ๋์ด ๋ฐํ์ ๋น์ฉ์ด ์ ํ ์์ต๋๋ค.
// commonMain declares what it needs but cannot implement here
expect class Platform() {
val name: String
val osVersion: String
}
// Shared logic can now depend on Platform freely
fun analyticsUserAgent(): String {
val platform = Platform()
return "SharpSkill/" + platform.name + " " + platform.osVersion
}Android ๊ตฌํ์ Build ํด๋์ค์์, iOS ๊ตฌํ์ UIDevice์์ ๊ฐ์ ์ฝ์ต๋๋ค. ๋ ๋ค ๊ฐ์ ๊ณ์ฝ์ ์ถฉ์กฑํ๋ฏ๋ก commonMain์ ์์ ์ด ์ด๋ ์ชฝ๊ณผ ๋ํํ๋์ง ๊ฒฐ์ฝ ์์ง ๋ชปํฉ๋๋ค.
import android.os.Build
// actual supplies the Android-specific implementation
actual class Platform actual constructor() {
actual val name: String = "Android"
actual val osVersion: String = Build.VERSION.RELEASE
}import platform.UIKit.UIDevice
// actual uses UIKit directly, no Objective-C bridging code required
actual class Platform actual constructor() {
actual val name: String = "iOS"
actual val osVersion: String = UIDevice.currentDevice.systemVersion
}Kotlin/Native๋ iOS SDK ์ ์ฒด์ ๋ํ ํ์
์ง์ ๋ฐ์ธ๋ฉ์ ํจ๊ป ์ ๊ณตํ๋ฏ๋ก UIDevice, NSUserDefaults, Foundation ํ์
์ ์์ผ๋ก ์์ฑํ ์ฐ๊ฒฐ ์ฝ๋ ์์ด Kotlin์์ ํธ์ถํ ์ ์์ต๋๋ค.
๋คํธ์ํน๊ณผ ์ง๋ ฌํ ๋ก์ง ๊ณต์ ํ๊ธฐ
๋คํธ์ํน์ API ๊ณ์ฝ์ด ์์ชฝ ํ๋ซํผ์์ ๋์ผํ๊ธฐ ๋๋ฌธ์ ๊ณต์ ๊ฐ์น๊ฐ ๊ฐ์ฅ ๋์ ์ฝ๋์
๋๋ค. ํ๋์ Ktor ํด๋ผ์ด์ธํธ์ kotlinx.serialization์ด ๋ ๊ฐ์ ๋ณ๋ ฌ ๊ตฌํ์ ๋์ฒดํฉ๋๋ค. suspend ํจ์๋ Kotlin ์ฝ๋ฃจํด์ ์์กดํ๋ฉฐ, ์์ชฝ์์ async/await๋ก ๊น๋ํ๊ฒ ๋์๋ฉ๋๋ค.
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.request.get
import io.ktor.serialization.kotlinx.json.json
import kotlinx.serialization.Serializable
// One serializable model, zero duplication across platforms
@Serializable
data class Question(val id: String, val prompt: String, val difficulty: String)
// One HttpClient, one JSON parser, one repository for both apps
class InterviewRepository {
private val client = HttpClient {
install(ContentNegotiation) { json() }
}
suspend fun fetchQuestions(tech: String): List<Question> =
client.get("https://api.sharpskill.dev/questions/" + tech).body()
}์ด ๋ฆฌํฌ์งํ ๋ฆฌ์ ๊ทธ ์ฌ์๋ ๋ก์ง, ๋ฐ์ดํฐ ๋ชจ๋ธ์ ํ ๋ฒ๋ง ์์ฑ๋ฉ๋๋ค. ํ์์์ ๊ณ ์น ๋ฒ๊ทธ๋ Android์ iOS์์ ๋์์ ๊ณ ์ณ์ง๋ฉฐ, ๋ฐ๋ก ์ด ์ง์ ์์ KMP๊ฐ ๋์
๋น์ฉ์ ํ์ํฉ๋๋ค. ๊ฐ์ ํจํด์ด SQLDelight๋ฅผ ์ด์ฉํ ๊ณต์ ๋ฐ์ดํฐ๋ฒ ์ด์ค, ๊ณต์ ํค-๊ฐ ์ ์ฅ์, Koin์ ์ด์ฉํ ๊ณต์ ์์กด์ฑ ์ฃผ์
์ผ๋ก๋ ํ์ฅ๋๋ฏ๋ก, ๋ฐ์ดํฐ ๊ณ์ธต ์ ์ฒด๋ฅผ UI๊ฐ ์์กดํ๋ ์ธํฐํ์ด์ค ๋ค์ commonMain์ ๋ ์ ์์ต๋๋ค.
ํํ ์ค์๋ ๋๋ฌด ์ด๋ฅธ ์์ ์ ๋๋ฌด ๋ง์ ๊ฒ์ ๊ณต์ ํ๋ ค๋ ๊ฒ์ ๋๋ค. ์ค์ฉ์ ์ธ ๋ฐฉ๋ฒ์ ๋จผ์ ๋ฆฌํฌ์งํ ๋ฆฌ ํ๋๋ก ์์ํด ์์ชฝ ํ๋ซํผ์์ ๋น๋์ CI ํ์ดํ๋ผ์ธ์ ๊ฒ์ฆํ ๋ค, ์์ ๊ฐ์ด ๋ถ์์๋ก ๊ธฐ๋ฅ์ ํ๋์ฉ ์ฎ๊ธฐ๋ ๊ฒ์ ๋๋ค.
Android ๋ฉด์ ์ค๋น๊ฐ ๋์ จ๋์?
์ธํฐ๋ํฐ๋ธ ์๋ฎฌ๋ ์ดํฐ, flashcards, ๊ธฐ์ ํ ์คํธ๋ก ์ฐ์ตํ์ธ์.
Compose Multiplatform์ผ๋ก ๊ณต์ UI ๊ตฌ์ถํ๊ธฐ
Compose Multiplatform์ 2025๋
5์์ iOS์์ ์์ ๋ฒ์ (1.8.0)์ ๋๋ฌํ๊ณ , 2026๋
์ค๋ฐ์๋ ๋ค์ดํฐ๋ธ ํ
์คํธ ์
๋ ฅ๊ณผ ๊ธฐ๋ณธ ํ์ฑํ๋ ๋์ ๋ ๋๋ง์ ๊ฐ์ถ 1.11.0์ ์ด๋ฅด๋ ์ต๋๋ค. commonMain์ ์๋ @Composable์ ์์ชฝ ํ๋ซํผ์์ ๋ ๋๋ง๋๋ฉฐ, ๊ณต์ ๋ทฐ ๋ชจ๋ธ์ MVVM ๋๋ MVI ์ํคํ
์ฒ์ ์์ฐ์ค๋ฝ๊ฒ ์ด์ธ๋ฆฝ๋๋ค.
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Card
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.foundation.layout.padding
// This list renders identically on Android and iOS
@Composable
fun QuestionList(questions: List<Question>) {
LazyColumn {
items(questions) { question ->
Card(modifier = Modifier.padding(8.dp)) {
Text(text = question.prompt, modifier = Modifier.padding(16.dp))
}
}
}
}UI ๊ณต์ ๋ ์ ํ ์ฌํญ์ด๋ฉฐ ํ๋ฉด ๋จ์์ ๋๋ค. ํ์ Compose Multiplatform์ผ๋ก ์ธํฐํ์ด์ค ์ ์ฒด๋ฅผ ๊ณต์ ํ ์๋, ์ฑ ์ ์ฒด๋ฅผ SwiftUI๋ก ์ ์งํ ์ฑ ๋ก์ง๋ง ๊ณต์ ํ ์๋, ๋์ ์์ ์๋ ์์ต๋๋ค. ์์ ฏ์ด๋ App Clip์ฒ๋ผ ํ๋ซํผ๋ณ UX์ ์์กดํ๋ ํ๋ฉด์ ๋ณดํต ๋ค์ดํฐ๋ธ๋ก ๋จ๊น๋๋ค.
iOS์์ Swift๋ก ๊ณต์ ์ฝ๋ ์ฌ์ฉํ๊ธฐ
๊ณต์ ๋ชจ๋์ Swift๊ฐ ์ฌ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ฒ๋ผ ์ํฌํธํ๋ ํ๋ ์์ํฌ๋ก ์ปดํ์ผ๋ฉ๋๋ค. ์ญ์ฌ์ ์ผ๋ก ๋ง์ฐฐ์ด ๋์๋ ๋ถ๋ถ์ Kotlin์ suspend ํจ์์ Flow๊ฐ ์ด์ํ ์ฝ๋ฐฑ API๋ก ๋๋ฌ๋๋ค๋ ์ ์ด์์ต๋๋ค. Touchlab์ SKIE๋ ๊ด์ฉ์ ์ธ Swift๋ฅผ ์์ฑํด ์ด๋ฅผ ํด๊ฒฐํฉ๋๋ค. suspend๋ ๋ค์ดํฐ๋ธ async/await๊ฐ ๋๊ณ Flow๋ AsyncSequence๊ฐ ๋ฉ๋๋ค.
import SwiftUI
import Shared // the KMP framework, baseName = "Shared"
struct ContentView: View {
@State private var questions: [Question] = []
private let repository = InterviewRepository()
var body: some View {
List(questions, id: \.id) { question in
Text(question.prompt)
}
.task {
// With SKIE, the Kotlin suspend fun is a Swift async fun
questions = (try? await repository.fetchQuestions(tech: "android")) ?? []
}
}
}iOS ํ์ ํ๋ฒํ Swift์ SwiftUI๋ฅผ ์์ฑํฉ๋๋ค. ์ด๋ค์ ๊ณต์ ๋ชจ๋ธ๊ณผ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ๋ค์ดํฐ๋ธ Swift ํจํค์ง์ ๋๊ฐ์ด ์ฌ์ฉํ๋ฏ๋ก, KMP๋ iOS ์ฝ๋๋ฒ ์ด์ค์ ๋๋ถ๋ถ์์ ๋ณด์ด์ง ์๋ ์ํ๋ก ๋จ์ต๋๋ค.
๋ฉด์ ์์ ์ธ๊ธํ ๊ฐ์น๊ฐ ์๋ ๊ฑฐ์น ๋ถ๋ถ์ด ์์ง ๋ ๊ฐ์ง ์์ต๋๋ค. ์ฒซ์งธ๋ ๋น๋ ์๊ฐ์ ๋๋ค. Kotlin/Native ์ปดํ์ผ์ ์์ Swift ๋น๋๋ณด๋ค ๋๋ฆฌ์ง๋ง, Gradle ๋น๋ ์บ์์ ๋ฏธ๋ฆฌ ๋น๋๋ XCFramework ๋ฐฐํฌ๊ฐ ์ผ์์ ์ธ ๋น์ฉ์ ์ํํฉ๋๋ค. ๋์งธ๋ Swift์์ Kotlin์ผ๋ก ๋์ด๊ฐ๋ ๊ฒฝ๊ณ์์์ ๋๋ฒ๊น ์ ๋๋ค. ๊ฐ์ ๋๊ณ ์์ง๋ง ํ๋์ ์ธ์ด์ ๋จธ๋ฌด๋ฅผ ๋๋งํผ ์์ง ๋งค๋๋ฝ์ง๋ ์์ต๋๋ค. ์ด ๋ํ ํ์ด ๊ณต์ ๋ฒ์๋ฅผ ๋ฌด์ง์ํ๊ฒ ๋ํ๊ธฐ๋ณด๋ค ์๋์ ์ผ๋ก ์ ์งํ๋ ๋ ํ๋์ ์ด์ ์ ๋๋ค.
์์๋๋ Kotlin Multiplatform ๋ฉด์ ์ง๋ฌธ
KMP ๋ฉด์ ์ง๋ฌธ์ Android์ ๋ชจ๋ฐ์ผ ์ง๋ฌด์์ ์ ์ ๋ ์์ฃผ ๋ฑ์ฅํ๋ฏ๋ก, ํญ๋์ Android ๋ฉด์ ์ค๋น์ ํจ๊ป ๋ฐ๋ณต๋๋ ๋ช ๊ฐ์ง๋ฅผ ์ฐ์ตํด ๋ ๊ฐ์น๊ฐ ์์ต๋๋ค.
- expect/actual์ ์ธํฐํ์ด์ค์ ์ด๋ป๊ฒ ๋ค๋ฆ ๋๊น? expect/actual์ ๋ฐํ์ ๋์คํจ์น ์์ด ํ๊น๋ณ๋ก ์ปดํ์ผ ์์ ์ ํด๊ฒฐ๋๋ฉฐ, ํด๋์ค, ํจ์, ํ๋กํผํฐ, typealias๋ฅผ ๋ท๋ฐ์นจํ ์ ์์ต๋๋ค. ์ธํฐํ์ด์ค๋ ๋ฐํ์์ ๋์ ์ผ๋ก ํด๊ฒฐ๋ฉ๋๋ค. ํ๋ซํผ API์๋ expect/actual์, ๊ณต์ ์ฝ๋ ๋ด๋ถ์ ๋คํ์ฑ์๋ ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํฉ๋๋ค.
- Kotlin/Native๋ ๋ฉ๋ชจ๋ฆฌ์ ์ค๋ ๋ฉ์ ์ด๋ป๊ฒ ๋ค๋ฃน๋๊น? Kotlin 1.7.20๋ถํฐ ์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ์๊ฐ ๊ธฐ์กด์ ๊ฐ์ฒด ๋๊ฒฐ ๋ชจ๋ธ์ ์์ด๊ธฐ ๋๋ฌธ์, ๊ณต์ ๋๋ ๊ฐ๋ณ ์ํ์ ์ฝ๋ฃจํด์ด JVM์์์ ๊ฑฐ์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ค๋ ๋๋ฅผ ๋๋๋ค๋ฉฐ ๋์ํฉ๋๋ค.
- ๊ธฐ์กด ์ฑ์ด KMP๋ฅผ ์ ์ง์ ์ผ๋ก ๋์ ํ ์ ์์ต๋๊น? ์. ๊ณต์ ๋ชจ๋์ Android์ฉ์ผ๋ก๋ AAR, iOS์ฉ์ผ๋ก๋ XCFramework๋ก ๋ฐฐํฌ๋๋ฏ๋ก ์ฌ์์ฑ ์์ด ๋ฆฌํฌ์งํ ๋ฆฌ๋ ๊ธฐ๋ฅ ํ๋์ฉ ์ด์ ํ ์ ์์ต๋๋ค.
- Compose Multiplatform ๋์ UI๋ฅผ ๋ค์ดํฐ๋ธ๋ก ๋จ๊ฒจ์ผ ํ ๋๋ ์ธ์ ์ ๋๊น? ํ๋ฉด์ด ํ๋ซํผ๋ณ UX์ ํฌ๊ฒ ์์กดํ ๋, ๋๋ iOS ํ์ด ํ๋ ์ ํ ์ด์ ๊ณ์ธต์ ์์ ํ๊ณ ์ง์ ์ ์ดํ๊ธฐ๋ฅผ ์ํ ๋์ ๋๋ค.
K2 ์ปดํ์ผ๋ฌ๋ฅผ ๊ฐ์ถ Kotlin 2.3, ๋คํธ์ํน์๋ Ktor 3.x, ๊ณต์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์๋ SQLDelight, ์์กด์ฑ ์ฃผ์ ์๋ Koin์ ๋ชฉํ๋ก ์ผ์ต๋๋ค. iOS ์ํธ์ด์ฉ์ ์ํด์๋ SKIE๋ฅผ ์ผ์ฐ ์ถ๊ฐํฉ๋๋ค. Swift ๊ณ์ธต์ ์์ฑํ ๋ค์ ๋์ค์ ๋ผ์ ๋ฃ๋ ๊ฒ์ ํจ์ฌ ๋ ๊ณ ํต์ค๋ฝ์ต๋๋ค.
๊ฒฐ๋ก
2026๋ ์ Kotlin Multiplatform์ ๋ค์ดํฐ๋ธ UI๋ ์ฑ๋ฅ์ ํฌ๊ธฐํ์ง ์์ผ๋ฉด์ Android์ iOS์ ๊ฑธ์น ์ค๋ณต ๋ก์ง์ ์ค์ด๋ ์ค์ฉ์ ์ธ ๋ฐฉ๋ฒ์ ๋๋ค.
- ๋จ์ผ ์ง์ค ๊ณต๊ธ์์ ๊ฐ์ง ๋ก์ง(๋ชจ๋ธ, ๋คํธ์ํน, ๊ฒ์ฆ)์ ๊ณต์ ํ๊ณ , ํ๋ฉด๋ง๋ค ๋ค์ดํฐ๋ธ UI์ Compose UI ์ค์์ ์ ํํฉ๋๋ค.
- ํ๋ซํผ API์๋
expect/actual์ ์ฌ์ฉํฉ๋๋ค. ์ปดํ์ผ ์์ ์ ํด๊ฒฐ๋์ด ๋ฐํ์ ์ค๋ฒํค๋๊ฐ ์์ต๋๋ค. - Ktor์
kotlinx.serialization์ผ๋ก ๋คํธ์ํน์ ํ ๋ฒ๋ง ์์ฑํ๋ฉด ์์ ์ด ์์ชฝ ํ๋ซํผ์ ๋์์ ๋ฐ์๋ฉ๋๋ค. - ์ฌ์์ฑ์ ๋ชฐ๋ํ๋ ๋์ AAR๊ณผ XCFramework๋ฅผ ํตํด ์ ์ง์ ์ผ๋ก ๋์ ํฉ๋๋ค.
- ์ฒ์๋ถํฐ SKIE๋ฅผ ์ถ๊ฐํด Swift๊ฐ
suspend์Flow๋ฅผ ๋ค์ดํฐ๋ธasync/await์AsyncSequence๋ก ์ฌ์ฉํ๊ฒ ํฉ๋๋ค.
์ฐ์ต์ ์์ํ์ธ์!
๋ฉด์ ์๋ฎฌ๋ ์ดํฐ์ ๊ธฐ์ ํ ์คํธ๋ก ์ง์์ ํ ์คํธํ์ธ์.
ํ๊ทธ
๊ณต์
๊ด๋ จ ๊ธฐ์ฌ

Android 16 ์์ ๋ถ์: ์๋ก์ด API, ๋ฐ์คํฌํฑ ๋ชจ๋, ๋ฉด์ ๋๋น ๊ฐ์ด๋
Android 16(API 36)์ ํต์ฌ ๋ณ๊ฒฝ์ฌํญ์ ์ฌ์ธต ๋ถ์ํฉ๋๋ค. Edge-to-Edge ๊ฐ์ ์ ์ฉ, ๋ฐ์คํฌํฑ ๋ชจ๋, ProgressStyle ์๋ฆผ, Predictive Back ์ ์ค์ฒ ๋ฑ 2026๋ ์๋๋ก์ด๋ ๊ฐ๋ฐ์ ๋ฉด์ ํ์ ์ฃผ์ ๋ฅผ ๋ค๋ฃน๋๋ค.

Kotlin Flow vs StateFlow vs SharedFlow: 2026 ์๋๋ก์ด๋ ๋ฉด์ ์ง๋ฌธ
2026๋ ์๋๋ก์ด๋ ๋ฉด์ ๊ด์ด ๋ฌป๋ Kotlin Flow vs StateFlow vs SharedFlow ์ง๋ฌธ์ ๋ช ํํ ๋ต๋ณ, ๋น๊ต ํ, ์ค๋ฌด์ฉ ์ฝ๋์ ํจ๊ป ์ ๋ฆฌํ์ต๋๋ค.

Android ์์กด์ฑ ์ฃผ์ : Hilt vs Koin ์์ ๊ฐ์ด๋ ๋ฐ ๋ฉด์ ์ง๋ฌธ 2026
Hilt์ Koin์ ์ฝ๋ ์์ , ์ฑ๋ฅ ๋ฒค์น๋งํฌ, ๋ฉด์ ์ง๋ฌธ์ผ๋ก ์ฒ ์ ํ ๋น๊ตํฉ๋๋ค. Hilt 2.57, Koin 4.2 ๊ธฐ๋ฐ 2026๋ ์ต์ ๊ฐ์ด๋.