メインコンテンツまでスキップ

Kotlin Multiplatform - UIの共有なし

このチュートリアルでは、Androidアプリケーションを作成し、Koinの依存性注入を使用してコンポーネントを取得する方法を説明します。 チュートリアルの所要時間は約 15分 です。

注記

更新 - 2024-10-21

コードを取得する

アプリケーション概要 (Application Overview)

このアプリケーションのアイデアは、ユーザーのリストを管理し、共有のPresenterを使用してネイティブUIに表示することです。

Users -> UserRepository -> Shared Presenter -> Native UI

「ユーザー (User)」データ

すべての共通/共有コードは、shared Gradleプロジェクトにあります。

ユーザーのコレクションを管理します。データクラスを以下に示します。

data class User(val name : String)

ユーザーのリストを管理する「リポジトリ (Repository)」コンポーネントを作成します(ユーザーの追加または名前による検索)。以下に、UserRepositoryインターフェースとその実装を示します。

interface UserRepository {
fun findUser(name : String): User?
fun addUsers(users : List<User>)
}

class UserRepositoryImpl : UserRepository {

private val _users = arrayListOf<User>()

override fun findUser(name: String): User? {
return _users.firstOrNull { it.name == name }
}

override fun addUsers(users : List<User>) {
_users.addAll(users)
}
}

共有Koinモジュール (Shared Koin module)

module関数を使用して、Koinモジュールを宣言します。Koinモジュールは、注入されるすべてのコンポーネントを定義する場所です。

最初のコンポーネントを宣言しましょう。UserRepositoryのシングルトンが必要なので、UserRepositoryImplのインスタンスを作成します。

module {
singleOf(::UserRepositoryImpl) { bind<UserRepository>() }
}

共有Presenter (Shared Presenter)

ユーザーを表示するPresenterコンポーネントを作成しましょう。

class UserPresenter(private val repository: UserRepository) {

fun sayHello(name : String) : String{
val foundUser = repository.findUser(name)
val platform = getPlatform()
return foundUser?.let { "Hello '$it' from ${platform.name}" } ?: "User '$name' not found!"
}
}

UserRepositoryは、UserPresenterのコンストラクタで参照されています。

UserPresenterをKoinモジュールで宣言します。factoryOf定義として宣言し、インスタンスをメモリに保持せず、ネイティブシステムに保持させます。

val appModule = module {
singleOf(::UserRepositoryImpl) { bind<UserRepository>() }
factoryOf(::UserPresenter)
}
注記

Koinモジュールは、iOS側からinitKoin()関数で簡単に実行できるように、実行する関数(ここではappModule)として使用できます。

ネイティブコンポーネント (Native Component)

次のネイティブコンポーネントは、AndroidとiOSで定義されています。

interface Platform {
val name: String
}

expect fun getPlatform(): Platform

どちらもローカルプラットフォームの実装を取得します。

Androidでの注入 (Injecting in Android)

すべてのAndroidアプリは、androidApp Gradleプロジェクトにあります。

UserPresenterコンポーネントが作成され、それと共にUserRepositoryインスタンスが解決されます。Activityに取得するには、koinInjectコンポーズ関数を使用して注入します。

// in App()

val greeting = koinInject<UserPresenter>().sayHello("Koin")

Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
Image(painterResource(Res.drawable.compose_multiplatform), null)
Text("Compose: $greeting")
}

これでアプリの準備が整いました。

備考

koinInject()関数を使用すると、Android ComposeランタイムでKoinインスタンスを取得できます。

AndroidアプリケーションでKoinを起動する必要があります。Composeアプリケーション関数AppKoinApplication()関数を呼び出すだけです。

fun App() {

KoinApplication(application = koinAndroidConfiguration(LocalContext.current)){
// ...
}
}

共有KMP構成からKoin Android構成を収集します。

// Android config
fun koinAndroidConfiguration(context: Context) : KoinAppDeclaration = {
androidContext(context)
androidLogger()
koinSharedConfiguration()
}
注記

LocalContext.currentを使用して、Composeから現在のAndroidコンテキストを取得します。

そして、共有KMP構成:

// Common config
fun koinSharedConfiguration() : KoinAppDeclaration = {
modules(appModule)
}
備考

modules()関数は、指定されたモジュールのリストをロードします。

iOSでの注入 (Injecting in iOS)

すべてのiOSアプリは、iosAppフォルダーにあります。

UserPresenterコンポーネントが作成され、それと共にUserRepositoryインスタンスが解決されます。ContentViewに取得するには、iOSのKoin依存関係を取得する関数を作成する必要があります。

// Koin.kt

fun getUserPresenter() : UserPresenter = KoinPlatform.getKoin().get()

それだけです。iOS側からKoinKt.getUserPresenter().sayHello()関数を呼び出すことができます。

import Shared

struct ContentView: View {

// ...
let greet = KoinKt.getUserPresenter().sayHello(name: "Koin")
}

iOSアプリケーションでKoinを起動する必要があります。Kotlin共有コードでは、initKoin()関数を使用して共有構成を使用できます。 最後に、iOSメインエントリで、上記のヘルパー関数を呼び出すKoinAppKt.doInitKoin()関数を呼び出すことができます。

@main
struct iOSApp: App {

init() {
KoinAppKt.doInitKoin()
}

//...
}