dorche
02/25/2025, 2:28 PMinternal
visibility modifier but I'm running into some issues. Details in threaddorche
02/25/2025, 2:31 PMinternal interface FooRepository { }
internal class FooRepositoryImpl() : FooRepository
I then need to define my the DI as
internal interface SharedRepositoryComponent {
@Provides
@Singleton
fun FooRepositoryImpl.bind(): FooRepository = this
}
dorche
02/25/2025, 2:35 PMpublic class BarViewModelFactory(
parent: AndroidApplicationComponent,
) : BarViewModelFactory(parent) {
override val factory: () -> BarViewModelFactoryImpl
get() {
require(parent is ScopedComponent)
return {
BarViewModelFactoryImpl(
viewModel = {
BarViewModel(
fooUseCase = (parent.sharedComponent as
ScopedComponent)._scoped.get("package.FooUseCase") {
with(parent.sharedComponent) {
(this as
ScopedComponent)._scoped.get("package.FooUseCaseImpl") {
FooUseCaseImpl(
accountsRepository = (this as
ScopedComponent)._scoped.get("package.FooRepository") {
(this as
ScopedComponent)._scoped.get("package.fooRepositoryImpl") {
FooRepositoryImpl()
}.bind()
}
)
}.bind()
}
}
)
}
)
}
}
}
dorche
02/25/2025, 2:36 PMCannot access 'FooRepositoryImpl': it is internal in 'package'
dorche
02/25/2025, 2:39 PMinternal
modifier helps reduce the size of the objc header so I assume everyone will try to have as little public
classes in their shared module as possibledorche
02/25/2025, 2:46 PMBarViewModel(
fooUseCase = (parent.sharedComponent as ScopedComponent)._scoped.get("package.FooUseCase") {
with(parent.sharedComponent) {
(this as ScopedComponent)._scoped.get("package.FooUseCaseImpl") {
FooUseCaseImpl( // <--- Here
accountsRepository = (this as ScopedComponent)._scoped.get("package.FooRepository") {
(this as ScopedComponent)._scoped.get("package.fooRepositoryImpl") {
FooRepositoryImpl() // <--- Here
}.bind()
}
)
}.bind()
}
}
)
Tldr - in snippet, the fact that _scoped.get()
gets passed an initialiser means that it needs to be able to access the classes which are now internal and defined in a different module
There's every chance that my view model generation factory code is wrong and what's causing the error but it didn't seems so to me and I'd like a 2nd opinion (or at least someone to tell me what I'm after is possible) before I sink tons of time into changing that...Marcelo Gobetti
04/21/2025, 7:48 PMinterface FooRepository { }
internal class FooRepositoryImpl() : FooRepository
these are the "workarounds" I've found from other modularized projects:
1. not use internal
, but that's not what you and I want, however personally I'd be open to being convinced that I don't need an internal class because kotlin-inject folks can solve the same problems in a different way
2. use `@Component abstract class`es instead of interfaces for the @Provides
methods. In an interface you can't make your methods internal, but in an abstract class you can, so this works internal fun FooRepositoryImpl.bind(): FooRepository = this
. The downside here is that your AppComponent can't inherit from multiple abstract classes, you'll have to actually inject (and build) those components
3. I suppose you have FooRepositoryImpl
annotated with @Inject
and this last workaround is to drop that annotation and build it yourself, but I find this kinda kills the purpose of a DI framework, although it might exceptionally be an acceptable tradeoff:
interface SharedRepositoryComponent {
@Provides
@Singleton
fun providesFooRepository(
foo: Foo,
bar: Bar
): FooRepository = FooRepositoryImpl(
foo = foo,
bar = bar
)
}
dorche
04/22/2025, 11:01 AMinternal
modifiers, not less. I have a "shared" KMP module that gets consumed by my iOS project (native UI but KMP for everything else) so with all this I'm trying to reduce what gets exposed in the Obj-C header file. Option 2 sounds okay tbh, as long as it doesn't turn out to be ton of boilerplate when try it out. Option 3 is also just about fine, I'll have a little play with both 2 and 3 to make sure I'm not missing some big downside for either. Thank you again for sharing!