使用 Koin 在 KMP 中进行依赖注入
在多平台项目中使用 Koin 连接共享模块。
使用 Koin 在 KMP 中进行依赖注入 是 CoddyKit 上的免费 Kotlin Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Kotlin Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Kotlin Academy 课程共包含 4 节课。
为什么在 KMP 中使用 DI
依赖注入会将组件的创建与使用解耦。在 KMP 中,Koin 是首选的 DI 框架,因为它是纯 Kotlin 编写的,并且无需注解处理器即可在 commonMain 中运行。
// 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 中启动 Koin
请在 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 ViewModel,请在 Android 模块中使用 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 使用 Lambda DSL,无需注解处理,非常适合 KMP。请在 commonMain 中定义共享模块,在平台源集中定义平台模块。使用 single 创建单例,使用 factory 创建全新实例,并使用 by inject() 进行延迟解析。
常见问题解答
「使用 Koin 在 KMP 中进行依赖注入」课时是免费的吗?
是的 — 「使用 Koin 在 KMP 中进行依赖注入」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Kotlin Academy 课程的其余内容,请升级到 CoddyKit PRO。 Kotlin Academy 课程共包含 4 节课。
「使用 Koin 在 KMP 中进行依赖注入」这节课中我会学到什么?
在多平台项目中使用 Koin 连接共享模块。 你通过在浏览器中直接运行的动手代码来练习 Kotlin Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Kotlin Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Kotlin Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「使用 Koin 在 KMP 中进行依赖注入」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Kotlin Academy 课中编写并运行代码吗?
能。每节 Kotlin Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- KMP 项目结构:commonMain、androidMain、iosMain
- 用于平台 API 的 expect/actual 机制
- 共享存储库层与用例层
- 使用 Koin 在 KMP 中进行依赖注入