InsertKoinIO / koin

Koin - a pragmatic lightweight dependency injection framework for Kotlin & Kotlin Multiplatform
https://insert-koin.io
Apache License 2.0
9.09k stars 719 forks source link

[Improvements] koin-androidx-startup setup and documentation #2012

Closed santimattius closed 3 weeks ago

santimattius commented 1 month ago

I have reviewed the new Koin startup implementation using App Startup and I think it's excellent that they have added this support. Some time ago I wrote a post about it "Koin Startup Extension: Configuring Koin using App Startup in Android".

What caught my attention, and the reason I'm addressing this here, is the KoinStartup object. This is used to maintain the reference of the Koin declaration, and the documentation indicates that we should call the onKoinStartup method in the init of our Application class. I think we could improve it by using the same strategy that WorkManager employs. Below, I share some code to visualize this idea.

First, we would need an interface to infer the declaration when the Initializer is executed

interface KoinDeclaration {

    fun declaration(): KoinAppDeclaration
}

We could also name it KoinStartup.

Then, we would have the implementation in our Application class:

class MainApplication : Application(), KoinDeclaration {

    override fun declaration(): KoinAppDeclaration = {
      androidLogger(Level.DEBUG)
      androidContext(this@MainApplication)
      modules(myModules)
    }
}

Once we have the implementation of KoinDeclaration in our Application class, we could perform the following verification in our Initializer

class KoinSingleInitializer : Initializer<Unit> {

    override fun create(context: Context) {
        if (context !is KoinDeclaration) {
            error("KoinInitializer can't start Koin configuration. Please implement KoinDeclaration interface in your Application class")
        }
        startKoin(context.declaration())
    }

    override fun dependencies(): List<Class<out Initializer<*>>> {
        return emptyList()
    }
}

At this point, we could also configure the androidContext, ensuring that it's always initialized.

Documentation

While the koin-startup functionality is still experimental, it would be beneficial to include information on how to use Koin in other initializers. This is especially relevant since App Startup allows specifying the dependency order. An illustrative example could be:

class CrashTrackerInitializer : Initializer<Unit>, KoinComponent {

    private val crashTrackerService: CrashTrackerService by inject()

    override fun create(context: Context) {
        crashTrackerService.configure(context)
    }

    override fun dependencies(): List<Class<out Initializer<*>>> {
        return listOf(KoinInitializer::class.java)
    }

}

I hope these ideas and suggestions are helpful. If you have any comments or additional proposals, please feel free to share them.

arnaudgiuliani commented 3 weeks ago

Yes I like your proposal. I tunned it like this:

@KoinExperimentalAPI
interface KoinStartup {

    /**
     * startKoin with AndroidX startup Initializer
     * @see startKoin function
     */
    @KoinApplicationDslMarker
    fun onKoinStartup() : KoinAppDeclaration
}
class KoinInitializer : Initializer<Koin> {

    @OptIn(KoinExperimentalAPI::class)
    override fun create(context: Context): Koin {
       return if (context is KoinStartup){
            startKoin(context.onKoinStartup()).koin
        } else error("Can't start Koin configuration on current Context. Please use KoinStartup interface to define your Koin configuration with.")
    }

    override fun dependencies(): List<Class<out Initializer<*>>> {
        return emptyList()
    }
}

And yes, documentation must be added to extend it to allow precise some dependency on it.

@santimattius do you have any feedback regarding impact with https://developer.android.com/google/play/integrity?

arnaudgiuliani commented 3 weeks ago

PR in follow: https://github.com/InsertKoinIO/koin/pull/2039

santimattius commented 3 weeks ago

Thanks @arnaudgiuliani! Regarding app integrity, I was reviewing the issue but I did not find any information on what could cause the error when app integrity is activated.

arnaudgiuliani commented 1 week ago

thanks @santimattius 👍