크로스 플랫폼 모바일 애플리케이션 만들기
코드 예제: tutorial-client-kmp
Ktor HTTP 클라이언트는 멀티플랫폼 프로젝트에서 사용할 수 있습니다. 이 튜토리얼에서는 요청을 보내고 응답 본문을 일반 HTML 텍스트로 받는 간단한 Kotlin Multiplatform Mobile 애플리케이션을 만들어 보겠습니다.
사전 준비
먼저, 적합한 운영 체제에 필요한 도구를 설치하여 크로스 플랫폼 모바일 개발 환경을 설정해야 합니다. 환경 설정 섹션에서 방법을 알아보세요.
이 튜토리얼의 특정 단계(iOS 전용 코드 작성 및 iOS 애플리케이션 실행 포함)를 완료하려면 macOS가 설치된 Mac이 필요합니다.
새 프로젝트 만들기
새 프로젝트를 만들려면 IntelliJ IDEA의 Kotlin Multiplatform 프로젝트 마법사를 사용할 수 있습니다. 이 마법사는 클라이언트와 서비스로 확장할 수 있는 기본 멀티플랫폼 프로젝트를 생성합니다.
- IntelliJ IDEA를 실행합니다.
- IntelliJ IDEA에서 File | New | Project를 선택합니다.
- 왼쪽 패널에서 Kotlin Multiplatform을 선택합니다.
- New Project 창에서 다음 필드를 지정합니다.
- Name: KmpKtor
- Group: com.example.ktor

- Android 및 iOS 타겟을 선택합니다.
- iOS의 경우, UI를 네이티브로 유지하기 위해 Do not share UI 옵션을 선택합니다.
- Create 버튼을 클릭하고 IDE가 프로젝트를 생성하고 임포트할 때까지 기다립니다.
빌드 스크립트 구성
Ktor 의존성 추가
프로젝트에서 Ktor HTTP 클라이언트를 사용하려면 최소 두 개의 의존성, 즉 클라이언트 의존성과 엔진 의존성을 추가해야 합니다.
- gradle/libs.versions.toml 파일을 열고 Ktor 버전을 추가합니다:kotlin
[versions] ktor = "3.4.0" 동일한 gradle/libs.versions.toml 파일에서 Ktor 클라이언트 및 엔진 라이브러리를 정의합니다:
kotlin[libraries] ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" } ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" }- shared/build.gradle.kts 파일을 열고 다음 의존성을 추가합니다:kotlin
sourceSets { commonMain.dependencies { implementation(libs.ktor.client.core) } androidMain.dependencies { implementation(libs.ktor.client.okhttp) } iosMain.dependencies { implementation(libs.ktor.client.darwin) } }- 공통 코드에서 Ktor 클라이언트 기능을 사용할 수 있도록
commonMain소스 세트에ktor-client-core를 추가합니다. androidMain소스 세트에는 Android에서OkHttp엔진을 사용하기 위해ktor-client-okhttp의존성을 포함합니다. 또는 사용 가능한 다른 Android/JVM 엔진 중에서 선택할 수 있습니다.iosMain소스 세트에는 iOS에서 Darwin 엔진을 사용하기 위해ktor-client-darwin의존성을 추가합니다.
- 공통 코드에서 Ktor 클라이언트 기능을 사용할 수 있도록
코루틴 추가
Android 코드에서 코루틴을 사용하려면 프로젝트에 kotlinx.coroutines를 추가해야 합니다:
- gradle/libs.versions.toml 파일을 열고 코루틴 버전과 라이브러리를 지정합니다:kotlin
[versions] kotlinx-coroutines = "1.10.2" [libraries] kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" } - shared/build.gradle.kts 파일을 열고
commonMain소스 세트에kotlinx-coroutines-core의존성을 추가합니다:kotlinsourceSets { commonMain.dependencies { implementation(libs.ktor.client.core) implementation(libs.kotlinx.coroutines.core) } } 그런 다음 composeApp/build.gradle.kts 파일을 열고
androidMain소스 세트에kotlinx-coroutines-android의존성을 추가합니다:kotlinsourceSets { androidMain.dependencies { // ... implementation(libs.kotlinx.coroutines.android) } }Build | Sync Project with Gradle Files를 선택하여 추가된 의존성을 설치합니다.
애플리케이션 업데이트
공통 코드 (Shared code)
Android와 iOS 간에 공유되는 코드를 업데이트하려면 shared/src/commonMain/kotlin/com/example/ktor/kmpktor/Greeting.kt 파일을 열고 Greeting 클래스에 다음 코드를 추가합니다:
package com.example.ktor.kmpktor
import io.ktor.client.HttpClient
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsText
class Greeting {
private val client = HttpClient()
suspend fun greet(): String {
val response = client.get("https://ktor.io/docs/")
return response.bodyAsText()
}
}HttpClient생성자는 HTTP 클라이언트를 생성합니다.- 일시 중단 함수(suspending function)인
greet()는 요청(request)을 보내고 응답(response)의 본문을 문자열 값으로 받습니다.
Android 코드
composeApp/src/androidMain/kotlin/com/example/ktor/kmpktor/App.kt 파일을 열고 다음과 같이 코드를 업데이트합니다:package com.example.ktor.kmpktor
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.safeContentPadding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import org.jetbrains.compose.ui.tooling.preview.Preview
@Composable
@Preview
fun App() {
MaterialTheme {
Column(
modifier = Modifier
.background(MaterialTheme.colorScheme.primaryContainer)
.safeContentPadding()
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
var text by remember { mutableStateOf("Loading") }
LaunchedEffect(true) {
text = try {
Greeting().greet()
} catch (e: Exception) {
e.message ?: "error"
}
}
GreetingView(text)
}
}
}
@Composable
fun GreetingView(text: String) {
Text(text = text)
}
@Preview
@Composable
fun DefaultPreview() {
MaterialTheme {
GreetingView("Hello, Android!")
}
}LaunchedEffect()는 컴포저블의 생명주기에 연결된 코루틴을 실행합니다. 이 코루틴 내에서 공유 greet() 함수가 호출되고, 그 결과가 text에 할당되며, 모든 예외가 포착되어 처리됩니다.
iOS 코드
iosApp/iosApp/ContentView.swift 파일을 열고 다음과 같이 코드를 업데이트합니다:import SwiftUI
import Shared
struct ContentView: View {
@StateObject private var viewModel = ViewModel()
var body: some View {
Text(viewModel.text)
}
}
extension ContentView {
@MainActor
class ViewModel: ObservableObject {
@Published var text = "Loading..."
init() {
Greeting().greet { greeting, error in
if let greeting = greeting {
self.text = greeting
} else {
self.text = error?.localizedDescription ?? "error"
}
}
}
}
}iOS에서 greet() 일시 중단 함수는 콜백이 있는 함수로 제공됩니다.
Android에서 인터넷 액세스 허용
마지막 단계는 Android 애플리케이션에 대해 인터넷 액세스를 허용하는 것입니다.
composeApp/src/androidMain/AndroidManifest.xml 파일을 열고<uses-permission> 요소를 사용하여 필요한 권한을 추가합니다:<manifest>
<uses-permission android:name="android.permission.INTERNET" />
<application>
...
</application>
</manifest>Android에서 애플리케이션 실행
IntelliJ IDEA의 실행 구성 목록에서 composeApp을 선택합니다.
구성 목록 옆에서 Android 가상 장치를 선택하고 Run을 클릭합니다.

목록에 장치가 없는 경우, 새 Android 가상 장치를 생성하세요.
로드가 완료되면 시뮬레이터에 수신된 HTML 문서가 일반 텍스트로 표시되어야 합니다.

Android 에뮬레이터가 인터넷에 연결되지 않는 경우, 콜드 부팅(cold boot)을 시도해 보세요. Device Manager 도구 창에서 중지된 장치 옆의 ⋮ (점 세 개)를 클릭하고 메뉴에서 Cold Boot를 선택합니다. 이는 종종 연결 문제를 일으킬 수 있는 손상된 에뮬레이터 캐시를 지우는 데 도움이 됩니다.
iOS에서 애플리케이션 실행
IntelliJ IDEA의 실행 구성 목록에서 iosApp을 선택합니다.
구성 목록 옆에서 iOS 시뮬레이션 장치를 선택하고 Run을 클릭합니다.

목록에 사용 가능한 iOS 구성이 없는 경우, 새 실행 구성을 추가하세요.
로드가 완료되면 시뮬레이터에 수신된 HTML 문서가 일반 텍스트로 표시되어야 합니다.

