Skip to content

Commit

Permalink
Merge pull request #2114 from InsertKoinIO/fix_compose_koin_application
Browse files Browse the repository at this point in the history
KoinMultiplatformApplication - Compose Application Start + Native Context binding
  • Loading branch information
arnaudgiuliani authored Jan 10, 2025
2 parents cfb1763 + b55088f commit 8dca6a9
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ import org.koin.dsl.koinConfiguration
import org.koin.dsl.includes

@Composable
internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinApplication.() -> Unit) : KoinConfiguration {
val current = LocalContext.current
internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinConfiguration) : KoinConfiguration {
val appContext = LocalContext.current.applicationContext ?: error("Android ApplicationContext not found in current Compose context!")
return koinConfiguration {
androidContext(current)
androidContext(appContext)
androidLogger(loggerLevel)
includes(config)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.currentComposer
import androidx.compose.runtime.remember
import org.koin.compose.application.rememberKoinApplication
import org.koin.compose.application.rememberKoinMPApplication
import org.koin.compose.error.UnknownKoinContext
import org.koin.core.Koin
import org.koin.core.KoinApplication
Expand All @@ -34,7 +35,6 @@ import org.koin.core.logger.Level
import org.koin.core.scope.Scope
import org.koin.dsl.KoinAppDeclaration
import org.koin.dsl.KoinConfiguration
import org.koin.dsl.koinApplication
import org.koin.mp.KoinPlatform
import org.koin.mp.KoinPlatformTools

Expand Down Expand Up @@ -105,12 +105,37 @@ private fun warningNoContext(ctx: Koin) {
}

/**
* Start a new Koin Application and associate it for Compose context
* if Koin's Default Context is already set,
* Start a new Koin Application context and setup Compose context
* if Koin's Default Context is already set, throw an error
*
* @param application - Koin Application declaration lambda
* @param content - following compose function
*
* @throws org.koin.core.error.KoinApplicationAlreadyStartedException
*
* @author Arnaud Giuliani
*/
@OptIn(KoinInternalApi::class)
@Composable
fun KoinApplication(
application: KoinAppDeclaration, //Better to directly use KoinConfiguration class
content: @Composable () -> Unit
) {
val koin = rememberKoinApplication(application)
KoinContext(koin,content)
}

/**
* Start a new Koin Application context, configure default context binding (android) & logger, setup Compose context
* if Koin's Default Context is already set, throw an error
*
* Call composeMultiplatformConfiguration to help prepare/anticipate context setup, and avoid to have different configuration in KMP app
* this function takes care to setup Android context (androidContext, androidLogger) for you
* @see composeMultiplatformConfiguration()
*
* @param application - Koin Application declaration lambda
* @param config - Koin Application Configuration (use koinConfiguration { } to declare your Koin application)
* @see KoinConfiguration
*
* @param logLevel - KMP active logger (androidLogger or printLogger)
* @param content - following compose function
*
Expand All @@ -120,13 +145,12 @@ private fun warningNoContext(ctx: Koin) {
*/
@OptIn(KoinInternalApi::class)
@Composable
fun KoinApplication(
application: KoinAppDeclaration,
fun KoinMultiplatformApplication(
config: KoinConfiguration,
logLevel : Level = Level.INFO,
content: @Composable () -> Unit
) {
val configuration = composeMultiplatformConfiguration(logLevel, config = application)
val koin = rememberKoinApplication(koinApplication(configuration))
val koin = rememberKoinMPApplication(config,logLevel)
KoinContext(koin,content)
}

Expand All @@ -135,7 +159,8 @@ fun KoinApplication(
* - Help handle automatically Android Logger Anticipate Android context injection, to having to setup androidContext() and androidLogger
*/
@Composable
internal expect fun composeMultiplatformConfiguration(loggerLevel : Level = Level.INFO, config : KoinApplication.() -> Unit) : KoinConfiguration
@PublishedApi
internal expect fun composeMultiplatformConfiguration(loggerLevel : Level = Level.INFO, config : KoinConfiguration) : KoinConfiguration

/**
* Use Compose with current existing Koin context, by default 'KoinPlatform.getKoin()'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,28 @@ package org.koin.compose.application

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import org.koin.compose.composeMultiplatformConfiguration
import org.koin.core.Koin
import org.koin.core.KoinApplication
import org.koin.core.annotation.KoinInternalApi
import org.koin.core.logger.Level
import org.koin.dsl.KoinAppDeclaration
import org.koin.dsl.KoinConfiguration
import org.koin.dsl.koinApplication

@Composable
internal inline fun rememberKoinApplication(noinline koinAppDeclaration: KoinAppDeclaration): Koin {
val wrapper = remember(koinAppDeclaration) {
CompositionKoinApplicationLoader(koinApplication(koinAppDeclaration))
}
return wrapper.koin ?: error("Koin context has not been initialized in rememberKoinApplication")
}

/**
* Remember Koin Application to handle its closure if necessary
*
* @param koinApplication
*
* @author Arnaud Giuliani
*/
@OptIn(KoinInternalApi::class)
@Composable
inline fun rememberKoinApplication(koinApplication: KoinApplication): Koin {
val wrapper = remember {
CompositionKoinApplicationLoader(koinApplication)
internal inline fun rememberKoinMPApplication(configuration: KoinConfiguration, logLevel: Level): Koin {
val configuration = composeMultiplatformConfiguration(logLevel, config = configuration)
val wrapper = remember(configuration,logLevel) {
CompositionKoinApplicationLoader(koinApplication(configuration))
}
return wrapper.koin ?: error("Koin context has not been initialized in rememberKoinApplication")
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import org.koin.dsl.includes
import org.koin.mp.KoinPlatform

@Composable
internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinApplication.() -> Unit) : KoinConfiguration {
internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinConfiguration) : KoinConfiguration {
return koinConfiguration {
printLogger(loggerLevel)
includes(config)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import org.koin.dsl.includes
import org.koin.mp.KoinPlatform

@Composable
internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinApplication.() -> Unit) : KoinConfiguration {
internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinConfiguration) : KoinConfiguration {
return koinConfiguration {
printLogger(loggerLevel)
includes(config)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import org.koin.dsl.includes
import org.koin.mp.KoinPlatform

@Composable
internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinApplication.() -> Unit) : KoinConfiguration {
internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinConfiguration) : KoinConfiguration {
return koinConfiguration {
printLogger(loggerLevel)
includes(config)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import org.koin.dsl.includes
import org.koin.mp.KoinPlatform

@Composable
internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinApplication.() -> Unit) : KoinConfiguration {
internal actual fun composeMultiplatformConfiguration(loggerLevel : Level, config : KoinConfiguration) : KoinConfiguration {
return koinConfiguration {
printLogger(loggerLevel)
includes(config)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ import org.koin.core.module.KoinApplicationDslMarker
//TODO Koin 4.1 - KoinAppDeclaration migration type to KoinConfiguration

/**
* Koin Configuration holder - use the koinConfiguration() function to define Koin configuration:
* Koin Configuration class holder, intended to replace KoinAppDeclaration that is a typealias on extension function
*
* use the koinConfiguration() function to define Koin configuration:
* koinConfiguration {
* modules(...)
* }
Expand Down

0 comments on commit 8dca6a9

Please sign in to comment.