skip to content
私的歌詞倉庫

Compose MultiplatformでKoinを使ってDI

/ 5 min read

Updated:
Table of Contents

はじめに

最近Kotlin Multiplatform(KMP)と、Compose Multiplatform(CMP)を使ってWeb開発をしています。Android開発の時のようにDIライブラリにHiltを使いたいなと思ったのですが、どうやら対応してないようだったのでKoinを選びました。最初は少し設定が難しかったのですが、どうにか動くところまでは出来ました。

各バージョンは以下の通りです。

ツールバージョン
Kotlin2.0.0
koin3.6.0-wasm-alpha2

3.6.0-wasm-alpha2 を使っているのですが、3.5系だとまだα版のWebのCMPを入れている影響か、そもそもライブラリを導入することが出来ませんでした。

解説に使ったコードはGitHubに公開しています。

GitHub - Tatsumi0000/nct-deck

Koinの使い方

インストール方法から、実装まで紹介したいと思います。

ライブラリのインストール

今回はVersion Catalogを使ってライブラリをインストールします。バージョン管理も楽になるので、BOMを使います。

[versions]
koin-bom = "3.6.0-wasm-alpha2"
[libraries]
koin-bom = { module = "io.insert-koin:koin-bom", version.ref = "koin-bom" }
koin-core = { module = "io.insert-koin:koin-core" }
koin-compose = { module = "io.insert-koin:koin-compose" }
koin-android = { module = "io.insert-koin:koin-android" }

composeAppのbuild.gradleにライブラリのバージョンを追記します(今回追記したものだけ記載しています)。

kotlin {
sourceSets {
androidMain.dependencies {
implementation(libs.koin.android)
}
commonMain.dependencies {
implementation(project.dependencies.platform(libs.koin.bom))
implementation(libs.koin.core)
implementation(libs.koin.compose)
}
}
}

commonMainにロジック部分を実装したいと思っているので、commonMainに書いています。Androidは今回使わないのですが、一応今後を見越して入れてます。

DI設定

実際にDIしたいコードです。interfaceを継承して文字列を返すための簡単な処理にしました。

interface HogeRepository {
fun sayHello(): String
}
class HogeRepositoryImpl: HogeRepository {
override fun sayHello(): String {
return "Hello from HogeRepositoryImpl"
}
}

次にKotinを使ってHogeRepositoryにHogeRepositoryImplをDIしてねと伝える設定です。

val hogeRepositoryModule = module {
singleOf(::HogeRepositoryImpl) bind HogeRepository::class
}

シングルトンで定義したいのでsingleOfを使います。single という書き方もあるようで、singleOfと等価とのことでした。

:: はクラスのプロパティやメソッドなどを値として取るためのもので、::class がクラスリテラルを取得するために使うもののようです(ChatGPTに聞いた)。多分、Koinが内部でDIするためにリフレクションしていい感じにするために必要なんだろうなと理解しました。

呼び出す

DI設定をしたのでさっそく呼び出します。@Composable でKoinApplicationを使ってDI設定を教えます。koinInjectを使ってinterfaceをジェネリクスに指定するとあとはKoinが勝手にインスタンス化します。今回だとHogeRepositoryImplのシングルトンなインスタンスを返します。

@Composable
@Preview
fun App() {
KoinApplication(application = {
modules(hogeRepositoryModule)
}) {}
MaterialTheme {
val repository = koinInject<HogeRepository>()
Button(onClick = {
println("Repository: ${repository.sayHello()}")
})
}
}

CMPアプリで使いたいのでKoinApplicationを使ってDIしています。

終わりに

Koinを使ったDIを初めて実践してみました。公式ドキュメントも結構充実していて、良かったです。Androidを開発するならHilt一択かなという気持ちですが、最近はKMPを使ったプロジェクトも多くなってきているような気がするので、Koinも使用頻度が増えていきそうです。

Koinマスターになるぞ!!!1

参考文献