Kotlin Academy · 강의

Koin을 사용한 KMP 의존성 주입

멀티플랫폼 설정에서 Koin으로 공유 모듈을 연결해 보세요.

레슨 4/414개 단계

Koin을 사용한 KMP 의존성 주입은(는) CoddyKit의 무료 Kotlin Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Kotlin Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Kotlin Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

KMP에서 DI가 필요한 이유

의존성 주입은 구성 요소 생성과 사용을 분리합니다. KMP에서는 애노테이션 프로세서 없이 순수 Kotlin으로 작성되고 commonMain에서 작동하므로 Koin이 대표적인 DI 프레임워크로 사용됩니다.

// No annotation processing needed — Koin uses lambda DSL
// Add to build.gradle.kts:
// implementation("io.insert-koin:koin-core:3.5.0")
// androidMain: koin-android
// iosMain: no extra dep
fun main() { println("Koin works on all KMP targets") }

Koin 모듈 DSL

module { } 블록에서 single, factory, scoped를 사용하여 바인딩을 정의합니다.

import org.koin.core.module.dsl.*
import org.koin.dsl.*
val appModule = module {
    single { HttpClient() }               // one instance
    single<UserRepository> { RemoteUserRepository(get()) }
    factory { GetUserUseCase(get()) }      // new instance each time
}

commonMain의 공유 모듈

commonMain에서 공유 Koin 모듈을 정의합니다. 플랫폼 모듈은 플랫폼별 바인딩으로 이를 확장합니다.

// commonMain/di/SharedModule.kt
import org.koin.dsl.module
fun sharedModule() = module {
    single<UserRepository> { RemoteUserRepository(get()) }
    single { GetUserUseCase(get()) }
    single { UserViewModel(get()) }
}

androidMain의 플랫폼 모듈

플랫폼 모듈은 실제 HTTP 엔진, 데이터베이스 드라이버, Android 전용 싱글턴을 제공합니다.

// androidMain/di/AndroidModule.kt
import io.ktor.client.engine.okhttp.*
import org.koin.dsl.module
fun androidModule() = module {
    single { OkHttp.create() }    // Ktor engine
    single { createHttpClient(get()) }
    includes(sharedModule())
}

Android Application에서 startKoin 시작하기

Android Application.onCreate에서 startKoin { }을 호출합니다. androidContext(this)를 사용하여 컨텍스트를 사용할 수 있게 합니다.

// androidMain:
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin
// In Application.onCreate():
startKoin {
    androidContext(this@MyApp)
    modules(androidModule())
}

iOS에서 Koin 시작하기

iOS에서는 Swift의 AppDelegate 또는 App 구조체에서 KoinApplication.start()를 호출하고 공유 Koin 모듈을 전달합니다.

// iosMain/KoinInit.kt:
import org.koin.core.context.startKoin
fun initKoin() {
    startKoin {
        modules(iosModule())
    }
}
// Swift: KoinInitKt.doInitKoin() in AppDelegate

의존성 해결

commonMain의 ViewModel이나 유스 케이스에서는 모듈 내부에서 get()을 사용하거나 호출 지점에서 inject() / getKoin().get()을 사용합니다.

import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
class UserViewModel : KoinComponent {
    private val getUser: GetUserUseCase by inject()
    fun load(id: String) = runBlocking { getUser(id) }
}

ViewModel을 위한 Koin 범위

Android 모듈에서는 Android ViewModels에 viewModel { }을 사용하고, 공유 VM에는 플랫폼에 종속되지 않는 factory { }를 사용합니다.

// androidMain (with koin-android):
import org.koin.androidx.viewmodel.dsl.viewModel
val androidVmModule = module {
    viewModel { UserViewModel(get()) }
}
// In Compose:
// val vm: UserViewModel = koinViewModel()

Koin을 사용한 테스트

테스트 설정에서 startKoin을 사용하고, 실제 종속성을 가짜 구현으로 교체하는 테스트 모듈을 사용합니다.

import org.koin.core.context.startKoin
import org.koin.core.context.stopKoin
import org.koin.dsl.module
class UserViewModelTest {
    @BeforeTest fun setup() {
        startKoin { modules(module {
            single<UserRepository> { FakeUserRepository() }
            single { GetUserUseCase(get()) }
        })}
    }
    @AfterTest fun teardown() = stopKoin()
}

single, factory, scoped 비교

single: 앱 수명 동안 하나의 인스턴스를 사용합니다. factory: get()이 호출될 때마다 새 인스턴스를 생성합니다. scoped: Koin 범위마다 하나의 인스턴스를 사용합니다(예: 화면 범위).

import org.koin.dsl.module
val lifetimeModule = module {
    single { Database() }           // shared, one instance
    factory { Analytics() }         // new on each get()
    scope<ScreenScope> {
        scoped { ScreenViewModel() } // one per screen lifecycle
    }
}

Koin, 수동 DI, Hilt 비교

Koin: 멀티플랫폼을 지원하고 KSP/KAPT가 필요 없으며 런타임 DI를 사용합니다. Hilt: Android 전용이며 컴파일 시점에 애노테이션을 기반으로 처리합니다. 수동 DI: 프레임워크 오버헤드 없이 가장 높은 제어력을 제공합니다. KMP 프로젝트에서는 공유를 위해 Koin을 사용합니다.

fun main() {
    // Koin  : commonMain, runtime, lambda DSL
    // Hilt  : androidMain only, compile-time
    // Manual: no framework, explicit wiring in factory/module files
    println("Choose Koin for KMP; Hilt for Android-only projects")
}

by inject()를 사용한 지연 주입

by inject()는 처음 접근할 때 의존성을 지연해서 해결합니다. KoinComponent를 구현하는 클래스에서 유용합니다.

import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
class AppService : KoinComponent {
    private val repo: UserRepository by inject()  // resolved on first use
    fun doWork() = println(repo.javaClass.simpleName)
}

빠른 확인

get()이 호출될 때마다 새 인스턴스를 생성하는 Koin 범위는 무엇입니까?

정리

Koin은 애노테이션 처리 없이 람다 DSL을 사용하므로 KMP에 적합합니다. 공유 모듈은 commonMain에, 플랫폼 모듈은 플랫폼 소스 세트에 정의합니다. 싱글턴에는 single을, 새 인스턴스에는 factory를, 지연된 해결에는 by inject()를 사용합니다.

무료로 시작

AI 튜터와 함께 Kotlin을(를) 배우세요 — 무료

브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.

코스
51
레슨
203

자주 묻는 질문

“Koin을 사용한 KMP 의존성 주입” 강의는 무료인가요?

네 — “Koin을 사용한 KMP 의존성 주입” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Kotlin Academy 강의 전체를 잠금 해제할 수 있습니다. Kotlin Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“Koin을 사용한 KMP 의존성 주입”에서 뭘 배우나요?

멀티플랫폼 설정에서 Koin으로 공유 모듈을 연결해 보세요. 브라우저에서 직접 실행하는 실습 코드로 Kotlin Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Kotlin Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Kotlin Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“Koin을 사용한 KMP 의존성 주입” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Kotlin Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Kotlin Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. KMP 프로젝트 구조: commonMain, androidMain, iosMain
  2. 플랫폼 API를 위한 expect/actual 메커니즘
  3. 저장소 및 사용 사례 계층 공유하기
  4. Koin을 사용한 KMP 의존성 주입
← Kotlin Academy(으)로 돌아가기