Skip to content

將 Koin 註解從 KSP 遷移至編譯器外掛程式

本指南將協助您將 Koin 註解專案從基於 KSP 的處理方式遷移至新的 Koin 編譯器外掛程式。

好消息!

您的註解將保持完全相同。 僅有組建組態與 Koin 啟動程式碼會發生變更。

有何不同?

面向KSP 處理編譯器外掛程式
處理KSP (獨立步驟)K2 編譯器 (整合)
產生的檔案build/generated/ksp 中可見無 — 內嵌轉換 (inline transformations)
組建速度較慢較快
KMP 設定每一平台專屬的 KSP 配置套用單一外掛程式
Koin 啟動modules(AppModule().module)startKoin<MyApp>()
未來支援已棄用積極開發中

系統需求

  • Kotlin 2.3.20+ (需要 K2 編譯器)
  • Gradle 8.x+

遷移步驟

步驟 1:更新 Kotlin 版本

編譯器外掛程式需要 Kotlin 2.3.20+:

kotlin
// build.gradle.kts
plugins {
    kotlin("jvm") version "2.3.20" // 最低要求為 2.3.20
}

步驟 2:更新版本目錄 (Version Catalog)

遷移前 (KSP):

toml
[versions]
koin = "4.0.0"
koin-ksp = "2.0.0"  # KSP 註解的獨立版本控制
ksp = "2.0.0-1.0.22"

[libraries]
koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }
koin-annotations = { module = "io.insert-koin:koin-annotations", version.ref = "koin-ksp" }
koin-ksp-compiler = { module = "io.insert-koin:koin-ksp-compiler", version.ref = "koin-ksp" }

[plugins]
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }

遷移後 (編譯器外掛程式):

toml
[versions]
koin = "4.2.0"
koin-plugin = "1.0.0"

[libraries]
koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }
koin-annotations = { module = "io.insert-koin:koin-annotations", version.ref = "koin" }

[plugins]
koin-compiler = { id = "io.insert-koin.compiler.plugin", version.ref = "koin-plugin" }

NOTE

koin-annotations 現在是 Koin 主專案的一部分,並使用與 koin-core 相同的版本。

步驟 3:更新組建組態

遷移前 (KSP):

kotlin
// build.gradle.kts
plugins {
    alias(libs.plugins.ksp)
}

dependencies {
    implementation(libs.koin.core)
    implementation(libs.koin.annotations)  // KSP 版本 (獨立版本控制)
    ksp(libs.koin.ksp.compiler)
}

ksp {
    arg("KOIN_CONFIG_CHECK", "true")
}

遷移後 (編譯器外掛程式):

kotlin
// build.gradle.kts
plugins {
    alias(libs.plugins.koin.compiler)
}

dependencies {
    implementation(libs.koin.core)
    implementation(libs.koin.annotations)  // 與 koin-core 版本相同
}

// 選用配置
koinCompiler {
    userLogs = true  // 記錄組件偵測
}

步驟 4:更新 Koin 啟動

這是主要的程式碼變更。KSP 方式使用產生的 .module 擴充套件,而編譯器外掛程式則使用具備 @KoinApplication 的具型別 API。

遷移前 (KSP):

kotlin
import org.koin.ksp.generated.*  // 產生的擴充套件

@Module
@ComponentScan("com.myapp")
class AppModule

fun main() {
    startKoin {
        modules(AppModule().module)  // 產生的 .module 擴充套件
    }
}

遷移後 (編譯器外掛程式):

kotlin
// 不需要產生的匯入

@Module
@ComponentScan("com.myapp")
class AppModule

@KoinApplication(modules = [AppModule::class])
class MyApp

fun main() {
    startKoin<MyApp>()  // 具型別 API
}

Android 範例

遷移前 (KSP):

kotlin
import org.koin.ksp.generated.*

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        startKoin {
            androidContext(this@MyApplication)
            modules(AppModule().module)
        }
    }
}

遷移後 (編譯器外掛程式):

kotlin
@KoinApplication(modules = [AppModule::class])
class MyApp

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        startKoin<MyApp> {
            androidContext(this@MyApplication)
        }
    }
}

步驟 5:清理

移除 KSP 產生的檔案並重新組建:

bash
rm -rf build/generated/ksp
./gradlew clean build

註解保持不變

所有加上註解的類別皆維持不變:

kotlin
// 無需變更!
@Singleton
class UserRepository(private val database: Database)

@Factory
class GetUserUseCase(private val repository: UserRepository)

@KoinViewModel
class UserViewModel(private val useCase: GetUserUseCase) : ViewModel()

@Module
@ComponentScan("com.myapp")
class AppModule

所有註解的功能完全相同。請參閱 註解參考 以取得完整清單。

匯入變更:@KoinViewModel

@KoinViewModel 註解的套件已變更:

kotlin
// 遷移前 (KSP)
import org.koin.android.annotation.KoinViewModel

// 遷移後 (編譯器外掛程式)
import org.koin.core.annotation.KoinViewModel

頂層函式定義 (新增)

編譯器外掛程式支援在頂層函式上使用註解,並透過 @ComponentScan 進行偵測:

kotlin
@Singleton
fun provideDatabase(): DatabaseService = PostgresDatabase()

@Factory
fun provideCache(db: DatabaseService): CacheService = RedisCache(db)

@Module
@ComponentScan("com.myapp")
class AppModule

函式傳回型別決定了繫結型別。函式參數將作為相依性注入。

DSL 語法變更

如果您在註解之外也使用 Koin DSL 模組,編譯器外掛程式引入了更簡潔的語法:

KSP / 經典風格編譯器外掛程式風格
singleOf(::MyService)single<MyService>()
factoryOf(::MyRepo)factory<MyRepo>()
viewModelOf(::MyVM)viewModel<MyVM>()
scopedOf(::MyScoped)scoped<MyScoped>()
workerOf(::MyWorker)worker<MyWorker>()
single { fn(get()) }single { create(::fn) }
kotlin
// 遷移前
val myModule = module {
    singleOf(::MyService)
    factoryOf(::MyRepository)
    viewModelOf(::MyViewModel)
}

// 遷移後
import org.koin.plugin.module.dsl.*

val myModule = module {
    single<MyService>()
    factory<MyRepository>()
    viewModel<MyViewModel>()
}

// 函式建置器 — 用於外部程式庫 (Room, Retrofit 等)
fun createDatabase(context: Context): AppDatabase =
    Room.databaseBuilder(context, AppDatabase::class.java, "db").build()

val dbModule = module {
    single { create(::createDatabase) }
}

NOTE

編譯器外掛程式 DSL 位於 org.koin.plugin.module.dsl 套件中。傳統 DSL 則保留在 org.koin.dsl 中。

跨模組偵測

使用 @Configuration 在 Gradle 模組之間進行自動模組偵測:

kotlin
// 在 feature 模組中
@Module
@ComponentScan
@Configuration
class FeatureModule

// 在 app 模組中 - FeatureModule 會被自動偵測
@KoinApplication
object MyApp

startKoin<MyApp>()  // FeatureModule 會自動被包含進來

KMP 遷移

編譯器外掛程式大幅簡化了 KMP 設定。

遷移前 (KSP) — 每一平台專屬的配置:

kotlin
// shared/build.gradle.kts
plugins {
    kotlin("multiplatform")
    id("com.google.devtools.ksp")
}

kotlin {
    sourceSets {
        commonMain.dependencies {
            implementation("io.insert-koin:koin-core:$koin_version")
            implementation("io.insert-koin:koin-annotations:$koin_ksp_version")  // 獨立版本
        }
    }
}

dependencies {
    // 每一平台都需要 KSP 編譯器
    add("kspAndroid", "io.insert-koin:koin-ksp-compiler:$koin_ksp_version")
    add("kspIosX64", "io.insert-koin:koin-ksp-compiler:$koin_ksp_version")
    add("kspIosArm64", "io.insert-koin:koin-ksp-compiler:$koin_ksp_version")
    add("kspIosSimulatorArm64", "io.insert-koin:koin-ksp-compiler:$koin_ksp_version")
}

遷移後 (編譯器外掛程式) — 單一外掛程式:

kotlin
// shared/build.gradle.kts
plugins {
    kotlin("multiplatform")
    alias(libs.plugins.koin.compiler)
}

kotlin {
    sourceSets {
        commonMain.dependencies {
            implementation(libs.koin.core)
            implementation(libs.koin.annotations)
        }
    }
}

具型別的啟動 API

編譯器外掛程式提供了具型別 API:startKoin<T>()koinApplication<T>()koinConfiguration<T>()

詳情請參閱 從註解開始

配置標籤 (新增)

編譯器外掛程式新增了配置標籤,用於條件式模組載入。

詳情請參閱 模組 - 配置

編譯器外掛程式選項

請參閱 編譯器外掛程式選項 以了解所有配置選項。

疑難排解

移除 KSP 後組建失敗

  1. ./gradlew clean
  2. rm -rf build/generated/ksp
  3. 失效 IDE 快取 (Invalidate IDE caches)
  4. 重新組建

未偵測到註解

啟用記錄功能:

kotlin
koinCompiler {
    userLogs = true
}

執行時缺少相依性

  1. 檢查 @ComponentScan 套件
  2. 驗證 @KoinApplication(modules = [...]) 中的模組
  3. 對外部相依性使用 @Provided

遷移檢查表

  • [ ] 將 Kotlin 更新至 2.3.20+
  • [ ] 將 Koin 更新至 4.2.0+
  • [ ] 移除 KSP 外掛程式
  • [ ] 移除 koin-ksp-compiler 相依性
  • [ ] 將 koin-annotations 更新至 Koin 主版本 (io.insert-koin:koin-annotations:$koin_version)
  • [ ] 新增 Koin 編譯器外掛程式 (io.insert-koin.compiler.plugin)
  • [ ] 將 @KoinViewModel 的匯入更新為 org.koin.core.annotation
  • [ ] 建立 @KoinApplication 類別,並將 modules(X().module) 替換為 startKoin<MyApp>()
  • [ ] 如果有使用 DSL 模組,將 DSL 匯入更新為 org.koin.plugin.module.dsl.*
  • [ ] 更新 DSL 語法:singleOf(::X)single<X>()
  • [ ] 移除 import org.koin.ksp.generated.*
  • [ ] 清理並重新組建 (rm -rf build/generated/ksp && ./gradlew clean build)

另請參閱