evant / kotlin-inject

Dependency injection lib for kotlin
Apache License 2.0
1.24k stars 55 forks source link

Cannot find an @Inject constructor or provider even though provided and created #314

Closed bmc08gt closed 11 months ago

bmc08gt commented 11 months ago

I hav an interface for creating a SettingsProvider on each platform defined as:

interface SettingsProvider {
    fun provide(): ObservableSettings
}

with the iOS and Android looking something to this effect:

@Inject
class IOSSettingsProvider: SettingsProvider {
    override fun provide(): ObservableSettings {
        return NSUserDefaultsSettings(
            NSUserDefaults.standardUserDefaults
        )
    }
}

It is being provided in a similar fashion to the greeter example, using a component graph of:

interface PlatformComponent {
    @Provides
    fun IOSSettingsProvider.bind(): SettingsProvider = this
}
@Component
abstract class ApplicationComponent: PlatformComponent {
    abstract val settingsProvider: SettingsProvider

    companion object {
        fun create() = ApplicationComponent::class.create()
    }
}

which is being created in ContentView.swift

var component = ApplicationComponent.companion.create()

I seem to be unable to provide the SettingsProvider via:

@Inject
class SettingsRepository(settingsProvider: SettingsProvider) {

    private val settings = settingsProvider.provide()

    val currency = StringSetting(settings, "currency", "USD ($)")
    val translateToEnglish = BooleanSetting(settings, "translate_to_english", true)

    fun clear() = settings.clear()
}

Is there a piece I am missing or is this a bug? Everything is being done in a single shared/ source dir

bmc08gt commented 11 months ago

Was able to invert App and Platform to get this to work.

commonMain

interface PlatformComponent {
    fun provideSettings(): SettingsProvider
}

androidMain

@AppScope
@Component
abstract class ApplicationComponent(
    @get:Provides val context: Context
): PlatformComponent {
    @Provides fun AndroidSettingsProvider.bind(): SettingsProvider = this
}

iosMain

@AppScope
@Component
abstract class ApplicationComponent: PlatformComponent {

    @Provides
    fun IOSSettingsProvider.bind(): SettingsProvider = this

    companion object {
        fun create() = ApplicationComponent::class.create()
    }
}
evant commented 11 months ago

👍 good tip, at some point it would be good to collect specific multi-platform guidance.

I think the original issue is because the processor is unable to 'see' the platform-specific bindings. Would have to dig into it more to see exactly why.