Kotlin Multiplatform

Kyu hyunSung·2025년 6월 1일

Multiplatform

목록 보기
1/1
post-thumbnail

2025년 5월 21일 기준
2025년 10월 24일 기준

패치노트 (2025년 10월 기준)

  • Compose Multiplatform for iOS 정식 출시 (Stable)
  • Swift Export 기본 지원
  • Compose Hot Reload 지원
  • JS/WasmJS 공유 소스셋 기본 제공
  • withJava() 함수 단계적 폐지 (Java 소스셋 기본 생성)

What is KMP ?

Kotlin Multiplatform : 원하는 방식으로 코드 공유

코틀린 멀티플랫폼은 JetBrains가 개발한 공식 크로스 플랫폼 개발 기술로, 개발자가 Kotlin으로 작성한 코드를 Android, iOS, 웹, 데스크톱, 서버 플랫폼에 배포할 수 있다.

개발자는 비즈니스 로직, 네트워킹, 상태 관리, 데이터 처리 등을 공통 모듈에서 공유하면서도, 플랫폼별 UI 구현은 네이티브로 유지할 수 있다.

Netflix, McDonald's, Cash App, Philips 같은 주요 기업들이 코틀린 멀티플랫폼을 도입하여 약 40%의 개발 효율성 향상과 코드 재사용성 개선을 달성했다곤함

2024년 5월 14일부터 Google은 비즈니스 로직을 모바일, 웹, 서버 및 데스크톱에서 공유하기 위한 도구로 KMP를 공식 승인.

2025년에서는 iOS 대상 플랫폼의 개발 경험 개선, IDE에서의 개발자 경험 향상, Compose Multiplatform for iOS의 안정화 (Kotlin-to-Swift), Amper라는 실험적 프로젝트 구성 및 빌드 도구를 Android와 iOS용 멀티플랫폼 모바일 앱 개발에 완전히 적합하도록 만드는 것도 주요 목표로 설정.

안드로이드, 데스크탑은 JVM을 통해서 빌드
IOS,Web은 Natvie로 빌드하는게 안정적임

Environment

Kotlin Multiplatform quickstart

OS

OS지원 상태비고
macOS✅ 전체 지원iOS 개발 필수
Windows⚠️ 제한적IntelliJ IDEA 2025.2.2+ 필요
Linux⚠️ 제한적IntelliJ IDEA 2025.2.2+ 필요

“To use the Kotlin Multiplatform IDE plugin on Windows and Linux, you need IntelliJ IDEA 2025.2.2. Android Studio will add support … in

⚠️ 주의: Windows/Linux는 KMP IDE 플러그인 지원이 제한적입니다. Android Studio는 향후 릴리스에서 지원 예정.

-> 윈도우랑 리눅스는 플러그인 문제가 있을 확률이 높음.

(윈도우는 Kotlin Multiplatform Plugin 지원 예정)

IDE

옵션 A: IntelliJ IDEA (권장)

버전: 2025.2.4 이상 (또는 2025.2+)
플러그인: Kotlin Multiplatform IDE Plugin
K2 모드: 기본 활성화 (2025.1+)

K2 Mode (IntelliJ IDEA 2025.1부터 기본 활성화)

옵션 B: Android Studio

버전: Narwhal 2025.1.1 Canary 10 이상

iOS 개발 (macOS 전용)

Xcode: 16.3 (최신 안정 버전)

Kotlin & Gradle

🔥 권장 안정 버전 조합 (2025.10.27 기준)

도구버전비고
Kotlin2.2.21최신 안정 버전
Compose Multiplatform1.9.1Kotlin과 자동 호환
Gradle8.6 ~ 8.148.6 권장
Android Gradle Plugin8.6.1-
JDK17 또는 21최소 11, 네이티브 배포는 17+
Xcode16.3macOS only

Kotlin: 2.2.21
Gradle: 7.6.3~8.14

참고 :Gradle 9.0 이상도 사용 가능하나 최신 버전이므로 안정성 확인 필요
Gradle 8.7-8.10도 지원하지만 withJava() 함수에서 deprecation 경고 발생

JDK

  • 최소 요구사항: JDK 11 이상
  • 네이티브 배포용: JDK 17 이상
  • 권장: JDK 17 또는 21


Kotlin Multiplatform wizard

설치 방법

그냥 이거 쓰셈

Template

  1. 공유 UI 멀티플랫폼
  • Shared UI : Compose
  • Shared logic : Kotlin
    ( Compose와 Kotlin으로 만사해결인척하는 에러 쓰레기들 )
MyApp/
├── composeApp/          # 공유 UI + 로직
│   └── src/
│       ├── commonMain/  # 모든 플랫폼 공통 코드
│       │   └── App.kt   # UI는 여기서 한번만 작성
│       ├── androidMain/ # Android 전용 (진입점만)
│       └── iosMain/     # iOS 전용 (진입점만)
└── iosApp/              # iOS 네이티브 래퍼
  • 코드 예시
// commonMain/App.kt - 한 번만 작성
@Composable
fun App() {
    MaterialTheme {
        Column {
            Text("Hello World")
            Button(onClick = { }) {
                Text("Click Me")
            }
        }
    }
}

  1. 네이티브 UI 멀티플랫폼 앱
  • Android : Jetpack Compose
  • IOS : SwiftUI
  • Shared Logic : Kotlin
    ( 정배 )
MyApp/
├── shared/              # 공유 로직만
│   └── src/
│       ├── commonMain/  # ViewModel, Repository 등
│       ├── androidMain/
│       └── iosMain/
├── androidApp/          # Android UI (Jetpack Compose)
│   └── MainActivity.kt
└── iosApp/              # iOS UI (SwiftUI)
    └── ContentView.swift
  • 코드예시
// androidApp - Android UI
@Composable
fun UserScreen(viewModel: UserViewModel) {
    LazyColumn {
        items(viewModel.loadUsers()) { user ->
            Text(user.name)  // Jetpack Compose
        }
    }
}
// iosApp - iOS UI
struct UserView: View {
    let viewModel = UserViewModel()
    
    var body: some View {
        List(viewModel.loadUsers()) { user in
            Text(user.name)  // SwiftUI
        }
    }
}
// shared/commonMain - 로직 공유
class UserViewModel {
    fun loadUsers(): List<User> { /* 공통 로직 */ }
}

  1. 멀티플랫폼 라이브러리
  • SDK나 유틸리티 라이브러리 개발
    (Ktor, SQLDelight, kotlinx-datetim 등등..)
  • 지원 플랫폼 : Android, iOS, Desktop (JVM), Server (JVM)
MyLibrary/
└── library/
    └── src/
        ├── commonMain/      # 공통 라이브러리 코드
        ├── androidMain/     # Android 구현
        ├── iosMain/         # iOS 구현
        └── jvmMain/         # Desktop/Server 구현]
  • 코드 예시
// commonMain
expect class Platform {
    fun getName(): String
}

fun greeting(): String = "Hello from ${Platform().getName()}"
// androidMain
actual class Platform {
    actual fun getName() = "Android"
}

// iosMain
actual class Platform {
    actual fun getName() = "iOS"
}

  1. Amper로 구성된 템플릿들 (실험적)
  • Gradle 대신 Amper씀

  • 존나 실험단계임 이런게있는지도 첨알았음

  • Amper Example

# Amper (module.yaml) - 간단함
product: app
platforms: [android, ios]
dependencies:
  - compose-runtime
  - ktor-client

  1. 직접 알아서 고르기
  • Android랑 데스크톱은 Compose로,
  • IOS는 안정화되었지만 SwiftUI가 나음
  • 웹은 베타버젼
  • Ktor은 아래 글 참고하셈
    ( 본인은 Ktor는 안쓸거임 )

Spring 공화국에서 Ktor 사용하기
[Android] Ktor란 무엇일까?

수동 작업 방법 : Kotlin Multiplatform quickstart

README.md

위에서 어떤걸 추가했냐에따라 README가 달라짐

This is a Kotlin Multiplatform project targeting Android, iOS.
Android와 iOS를 대상으로 하는 Kotlin Multiplatform 프로젝트입니다.

* `/composeApp` is for code that will be shared across your Compose Multiplatform applications.
* `/composeApp`은 Compose Multiplatform 애플리케이션 간에 공유될 코드를 위한 폴더입니다.

  It contains several subfolders:
  여러 하위 폴더를 포함합니다:

  - `commonMain` is for code that's common for all targets.
  - `commonMain`은 모든 대상에 공통적인 코드를 위한 폴더입니다.

  - Other folders are for Kotlin code that will be compiled for only the platform indicated in the folder name.
  - 다른 폴더들은 폴더 이름에 표시된 플랫폼에서만 컴파일될 Kotlin 코드를 위한 것입니다.

...

구조 구경하기

저거 한국어번역은 본인이 넣은거임

루트 디렉토리

KotlinProject/
├── README.md                    # 프로젝트 설명 파일
├── build.gradle.kts            # 루트 빌드 스크립트 (Kotlin DSL)
├── settings.gradle.kts         # 프로젝트 설정 파일
├── gradle.properties           # Gradle 설정 프로퍼티
├── local.properties            # 로컬 환경 설정 (Android SDK 경로 등)
├── package.json                # npm 패키지 설정 (웹 앱용)
├── gradlew                     # Gradle Wrapper 실행 파일 (Unix/Linux/Mac)
└── gradlew.bat                 # Gradle Wrapper 실행 파일 (Windows)

gradle/ 디렉토리

gradle/
├── libs.versions.toml          # 의존성 버전 카탈로그 (Version Catalog)
└── wrapper/
    ├── gradle-wrapper.jar      # Gradle Wrapper JAR 파일
    └── gradle-wrapper.properties # Gradle Wrapper 설정

shared/ 디렉토리 (공유 비즈니스 로직)

shared/
├── build.gradle.kts            # shared 모듈 빌드 스크립트
├── build/                      # 빌드 결과물
│   ├── internal/kmp/           # KMP 내부 빌드 파일
│   ├── kotlin/                 # Kotlin 컴파일 결과
│   │   └── commonizedNativeDistributionLocation.txt
│   ├── kotlinProjectStructureMetadata/ # 프로젝트 구조 메타데이터
│   │   └── kotlin-project-structure-metadata.json
│   └── tmp/                    # 임시 파일
└── src/                        # 소스 코드
    ├── androidMain/            # Android 플랫폼별 구현
    │   └── kotlin/
    │       └── org/example/project/
    │           └── Platform.android.kt  # Android 플랫폼 구현
    ├── commonMain/             # 모든 플랫폼 공통 코드
    │   └── kotlin/
    │       └── org/example/project/
    │           ├── Greeting.kt     # 공통 비즈니스 로직
    │           └── Platform.kt     # 플랫폼 추상화 인터페이스 (expect)
    ├── commonTest/             # 공통 테스트 코드
    │   └── kotlin/
    │       └── org/example/project/
    │           └── SharedCommonTest.kt
    ├── iosMain/                # iOS 플랫폼별 구현
    │   └── kotlin/
    │       └── org/example/project/
    │           └── Platform.ios.kt     # iOS 플랫폼 구현
    ├── jsMain/                 # Web (JavaScript) 플랫폼별 구현
    │   └── kotlin/
    │       └── org/example/project/
    │           └── Platform.js.kt      # JavaScript 플랫폼 구현
    └── jvmMain/                # Desktop (JVM) 플랫폼별 구현
        └── kotlin/
            └── org/example/project/
                └── Platform.jvm.kt     # JVM 플랫폼 구현

composeApp/ 디렉토리 (Compose Multiplatform UI 코드)

composeApp/
├── build.gradle.kts            # composeApp 모듈 빌드 스크립트
├── build/                      # 빌드 결과물 디렉토리
│   ├── generated/              # 자동 생성된 파일들
│   │   └── compose/
│   │       └── resourceGenerator/
│   │           ├── kotlin/     # 리소스 접근용 자동 생성 Kotlin 파일들
│   │           │   ├── androidMainResourceCollectors/   # Android 리소스 수집기
│   │           │   ├── commonMainResourceAccessors/     # 공통 리소스 접근자
│   │           │   ├── commonMainResourceCollectors/    # 공통 리소스 수집기
│   │           │   ├── commonResClass/                  # 공통 리소스 클래스 (Res.kt)
│   │           │   └── jvmMainResourceCollectors/       # JVM 리소스 수집기
│   │           └── preparedResources/                   # 준비된 리소스 파일들
│   │               └── commonMain/
│   │                   └── composeResources/
│   │                       └── drawable/
│   └── tmp/                    # 임시 빌드 파일
└── src/                        # 소스 코드 디렉토리
    ├── androidMain/            # Android 플랫폼 전용 코드
    │   ├── AndroidManifest.xml # Android 앱 매니페스트
    │   ├── kotlin/             # Android Kotlin 소스 코드
    │   │   └── org/example/project/
    │   │       └── MainActivity.kt # Android 메인 액티비티
    │   └── res/                # Android 네이티브 리소스
    │       ├── drawable/       # 일반 Drawable 리소스
    │       ├── drawable-v24/   # API 24+ Drawable 리소스
    │       ├── mipmap-anydpi-v26/  # 적응형 아이콘 (API 26+)
    │       ├── mipmap-hdpi/    # 고밀도 아이콘
    │       ├── mipmap-mdpi/    # 중밀도 아이콘
    │       ├── mipmap-xhdpi/   # 초고밀도 아이콘
    │       ├── mipmap-xxhdpi/  # 초초고밀도 아이콘
    │       ├── mipmap-xxxhdpi/ # 초초초고밀도 아이콘
    │       └── values/         # 문자열, 색상 등 값 리소스
    │           └── strings.xml
    ├── commonMain/             # 모든 플랫폼 공통 UI 코드
    │   ├── composeResources/   # Compose 공통 리소스
    │   │   └── drawable/       # 공통 Drawable 리소스
    │   │       └── compose-multiplatform.xml
    │   └── kotlin/             # 공통 Kotlin 코드
    │       └── org/example/project/
    │           └── App.kt      # 공통 앱 컴포넌트
    ├── commonTest/             # 공통 테스트 코드
    │   └── kotlin/
    │       └── org/example/project/
    │           └── ComposeAppCommonTest.kt
    └── jvmMain/                # Desktop (JVM) 플랫폼 전용 코드
        └── kotlin/
            └── org/example/project/
                └── main.kt     # Desktop 앱 진입점

iosApp/ 디렉토리 (iOS 네이티브 앱)

iosApp/
├── Configuration/
│   └── Config.xcconfig         # Xcode 빌드 설정
├── iosApp/                     # iOS 앱 소스 코드
│   ├── Assets.xcassets/        # iOS 앱 에셋 (아이콘, 색상 등)
│   │   ├── AccentColor.colorset/   # 강조 색상 세트
│   │   │   └── Contents.json
│   │   ├── AppIcon.appiconset/     # 앱 아이콘 세트
│   │   │   └── Contents.json
│   │   └── Contents.json
│   ├── ContentView.swift       # SwiftUI 메인 뷰
│   ├── Info.plist             # iOS 앱 정보 설정
│   ├── iOSApp.swift           # iOS 앱 진입점
│   └── Preview Content/        # SwiftUI 프리뷰용 에셋
│       └── Preview Assets.xcassets/
│           └── Contents.json
└── iosApp.xcodeproj/          # Xcode 프로젝트 파일
    ├── project.pbxproj        # Xcode 프로젝트 설정
    ├── project.xcworkspace/   # Xcode 워크스페이스
    │   ├── contents.xcworkspacedata
    │   ├── xcshareddata/
    │   │   └── swiftpm/
    │   │       └── configuration/
    │   └── xcuserdata/
    │       └── seong-gyuhyeon.xcuserdatad/
    │           └── xcschemes/
    │               └── xcschememanagement.plist
    └── xcuserdata/
        └── seong-gyuhyeon.xcuserdatad/
            └── xcschemes/
                ├── iosApp.xcscheme
                └── xcschememanagement.plist

webApp/ 디렉토리 (웹 React 애플리케이션)

webApp/
├── index.html                  # 웹 앱 HTML 진입점
├── package.json                # npm 패키지 의존성
├── tsconfig.json               # TypeScript 컴파일 설정
├── tsconfig.node.json          # Node.js용 TypeScript 설정
├── vite.config.ts              # Vite 빌드 도구 설정
└── src/                        # 웹 앱 소스 코드
    ├── index.tsx               # React 앱 진입점
    └── components/             # React 컴포넌트
        ├── Greeting/           # Greeting 컴포넌트
        │   ├── Greeting.css
        │   └── Greeting.tsx
        └── JSLogo/             # JSLogo 컴포넌트
            ├── JSLogo.css
            └── JSLogo.tsx

주요 개념 정리

composeApp vs shared

composeApp: UI 코드 (Compose Multiplatform)를 공유하는 모듈입니다. Android, iOS, Desktop, Web의 화면 구성을 담당합니다.

shared: 비즈니스 로직을 공유하는 모듈입니다. 네트워크, 데이터베이스, 도메인 로직 등 플랫폼에 독립적인 코드를 포함합니다.

플랫폼별 소스셋

소스셋용도
commonMain모든 플랫폼 공통 코드
androidMainAndroid 전용 구현
iosMainiOS 전용 구현
jvmMainDesktop (JVM) 전용
jsMainWeb (JavaScript) 전용
wasmJsMainWeb (WebAssembly) 전용

expect/actual 패턴

expect 선언: Platform.kt (commonMain)에서 플랫폼별 기능을 추상화합니다.

expect class Platform {
    fun getName(): String
}

actual 구현: 각 플랫폼 디렉토리에서 실제 구현을 제공합니다.

// Platform.android.kt - Android 구현
actual class Platform {
    actual fun getName() = "Android"
}
// Platform.ios.kt - iOS 구현
actual class Platform {
    actual fun getName() = "iOS"
}

빌드 시스템

Gradle: Android, Desktop, shared 모듈의 빌드를 관리합니다.

Xcode: iOS 앱의 빌드와 배포를 관리합니다.

Vite: 웹 앱의 개발 서버와 프로덕션 빌드를 담당합니다.

Version Catalog: libs.versions.toml 파일을 통해 의존성 버전을 중앙에서 관리합니다.

리소스 관리

composeResources: Compose Multiplatform 공통 리소스입니다.

Android res: Android 네이티브 리소스 (아이콘, 레이아웃, 문자열 등)입니다.

iOS Assets.xcassets: iOS 네이티브 에셋입니다.

자동 생성 코드: Compose 리소스는 빌드 시 자동으로 Kotlin 코드로 변환되어 타입 안전하게 접근할 수 있습니다.

빌드 방법

1. 안드로이드

안드로이드는 원래 하던듯이 빌드하면 된다.

  • 실제 기기 or 애뮬레이터 켜서

  • 걍 빌드 하면 끝ㅇㅇ

IOS 에서는 안됌.따로 해줘야하ㅣㅁ

이제는 안드로이드 스튜디오에서도 빌드가 잘됨
(2025.10.27 기준)

2. IOS

  • 제약사항

    ⚠️ macOS 전용: Xcode 필수, Windows/Linux에서 iOS 빌드 불가
    ⚠️ 성능: 레이아웃 지연, CPU 사용량 증가 가능
    ⚠️ 접근성: Compose 뷰가 XCTest에 제대로 노출되지 않음
    ⚠️ UI: Cupertino 컴포넌트 부재, Material Design 기본값

그럼에도 불구하고 SwiftUI니까 Xcode에서 Preview 보면서 빌드하는게 편할거임

  1. Xcode 프로젝트 열기

만약에 저렇게 모듈이 적용안된다고 뜨면

  1. IOS 프로젝트 설정
  • Xcode에서 Project navigator의 프로젝트 이름을 더블클릭하여 iOS 프로젝트 설정을 열기

  • 왼쪽 Targets 섹션에서 프로젝트를 선택한 후 Build Phases 탭을 클릭.
    ( 아이콘을 클릭하고 New Run Script Phase를 선택합니다. )

  • 생성된 Run Script 항목을 확장하고 텍스트 필드에 다음 스크립트 넣기.
    ( 오른쪽 Full Path 경로보고 따라 치면됨 )

cd "$SRCROOT/.."
./gradlew :shared:embedAndSignAppleFrameworkForXcode

만약 안돼면

cd "$SRCROOT/.."
./gradlew clean
./gradlew :shared:embedAndSignAppleFrameworkForXcode

  • 컴파일 전 단계로 드래그해서 올리기

  • User Script Sandboxing 비활성화

  • 그럼 이렇게 ContentView에서 프리뷰로도 볼 수 있음.

근데 IOS 안정화되서 그냥 Xcode로 파일 열기만 해도
웬만해선 될거임

안드로이드 스튜디오에서 작동시키기 - IOS 안정화로 해결

  • 이부분은 무시해도 좋음

### IOS 애뮬레이터 추가하기

1) 메인 메뉴에서 File | Sync Project with Gradle Files를 선택합니다. Android Studio가 자동으로 simpleLoginIOS라는 실행 구성을 생성합니다.
2) 실행 구성 목록에서 simpleLoginIOS를 선택합니다. iOS 시뮬레이터를 선택하고 Run을 클릭합니다.

  • 트러블이슈 : IOS 애뮬레이터를 찾질 못함.

06/03 정정 : 버젼이슈. 2025.1.1 이상 안드로이드로 설치.

- 트러블 이슈: 빌드는 됐으나 애뮬레이터에 뜨질 않음.

Failed waiting too long for the connection to be established

버젼을 다르게해도 똑같아서 그냥 포기.

#### 애뮬레이터 대안 방법

1) 아이폰을 직접 기기에 연결해서 사용하기


2) Xcode 상에서 UI 작업하고 돌리기
- Shard 모듈 임포트 필수

어차피 안드로이드 스튜디오에서 UI 볼수가 없어서 Xcode 키는게 낫긴 할듯.

3. Desktop 빌드

  • 제약사항

    ⚠️ 배포: 각 OS에서 해당 패키지만 빌드 가능 (크로스 컴파일 불가)

똑같이 안드로이드 스튜디오에서 실행시켜도 문제없음

여기서

이녀석 골라소 누르면됨

4. Web(React) 빌드

  • 제약사항

    ⚠️ 베타 단계: Compose Multiplatform for Web (얼리 어답터용)
    ⚠️ 브라우저 요구: Chrome 119+, Firefox 120+, Safari 일부 제한
    ⚠️ 성능: Kotlin/Wasm 사용 시 바이너리 크기 증가 (7~8MB)

  • 본인은 웹을 React+typescript로 개발하기를 선택해서 npm을 설치해줘야함

  • 그전에 가장 해야할건, Kotlin shared 모듈 빌드을 진행해줘야함

# npm용 라이브러리 빌드
./gradlew :shared:jsBrowserProductionLibrary

# 또는 배포용 번들 (전체배포파일)
./gradlew :shared:jsBrowserDistribution

혹은 걍 무지성 전체빌드

./gradlew :shared:build

그리고 다시 프로젝트 루트로 돌아와서

# 빌드 결과 확인
ls -la shared/build/dist/js/productionLibrary/

하면

대충 뭐 이렇게 나와야함

그다음에

  • package.json에서 로컬 경로로 참조
    ( 근데 이래도 되는건진 모르겠음;; )
# 3. npm 설치
npm install

# 4. 개발 서버 실행
npm run dev

로 실행시키기

성공
사람마다 포트는 조금씩 다를수있음.

과정은 다음과 같음

Kotlin 코드 작성 (shared)
         ↓
JavaScript로 컴파일 (Gradle)
         ↓
npm 패키지로 참조 (package.json)
         ↓
React에서 import (TypeScript)
         ↓
브라우저 실행 (Vite)

앞으로 Kotlin 서버코드가 바뀌면 매번 빌드해줘야함

# 1. shared 다시 빌드
./gradlew :shared:jsBrowserProductionLibrary

# 2. npm 재설치 (필요시)
cd webApp
rm -rf node_modules package-lock.json
npm install

# 3. 개발 서버 재시작
npm run dev

진짜 개귀찮긴한데 나중에 자동화방법에대해
따로 정리해봄

추가로

  • 만약에 Compose로 개발하기를 했으면
oneForAll/
├── composeApp/          # 모든 플랫폼의 UI + 로직
│   └── src/
│       ├── commonMain/  # 공통 UI (Compose)
│       ├── jvmMain/     # Desktop
│       └── wasmJsMain/  # Web
└── iosApp/

저렇게 wasmJSMain 으로 되어있을거임

그거는 Desktop처럼 바로 누르면 빌드해서 나올거임 아마도

안해봐서 나도 모름 알아서하셈


📚 참고 자료

공식 문서

로드맵

커뮤니티


profile
디지털 치매 예방

0개의 댓글