Skip to content Skip to sidebar Skip to footer

Android Dynamic Feature Modules With Dagger Hilt

I have built a Dynamic feature module sample with Fragments, sub components and dependent components based on plaid app, if you wish to check out here is the link. Now, i'm trying

Solution 1:

I finally figured it out.

For an app structure

FeatureCamera  FeaturePhotos  (Dynamic Feature Modules)  
||||----App||
core(android-library)

Camera dynamic feature module dependencies from core module, Photo dynamic feature module dependencies from app.

First create a CoreModule in library module

@InstallIn(ApplicationComponent::class)
@Module
class CoreModule {

    @Singleton@Provides
    fun provideCoreDependency(application: Application) = CoreDependency(application)

    @Provides
    fun provideCoreActivityDependency(context: Application) = CoreActivityDependency(context)

    @Provides
    fun provideCoreCameraDependency(): CoreCameraDependency = CoreCameraDependency()

    @Provides
    fun provideCorePhotoDependency(): CorePhotoDependency = CorePhotoDependency()
}

An interface with @EntryPoint is required to with provision methods defined in this interface, if you don't define a method for that dependency you cannot inject it even though there is a @Provides method for it. These are mock dependencies that take application or context as only parameter.

@EntryPoint@InstallIn(ApplicationComponent::class)interfaceCoreComponent{

    /*
        Provision methods to provide dependencies to components that depend on this component
     */funcoreDependency(): CoreDependency

    funcoreActivityDependency(): CoreActivityDependency

    funcoreCameraDependency(): CoreCameraDependency

    funcorePhotoDependency(): CorePhotoDependency
    
}

In camera dynamic feature module, create another module for the dependency based inside of this dynamic feature module.

@InstallIn(FragmentComponent::class)
@Module(includes = [CameraBindModule::class])
class CameraModule {

    @Provides
    fun provideCameraObject(context: Context) = CameraObject(context)
}

@InstallIn(FragmentComponent::class)
@Module
abstract class CameraBindModule {
    @Binds
    abstract fun bindContext(application: Application): Context
}

And component to inject dependencies to Fragments or Activities in this DFM.

@Component( dependencies = [CoreComponent::class], modules = [CameraModule::class] ) interface CameraComponent {

funinject(cameraFragment1: CameraFragment1)funinject(cameraFragment2: CameraFragment2)funinject(cameraActivity: CameraActivity)@Component.Factory
interfaceFactory{
    funcreate(coreComponent: CoreComponent, @BindsInstance application: Application): CameraComponent
}

}

If injected to Activity call in onCreate()

  DaggerCameraComponent.factory().create(
            EntryPointAccessors.fromApplication(
                    applicationContext,
                    CoreComponent::class.java
            ),
            application
    )
            .inject(this)

For injecting to Fragment call in onCreate()

DaggerCameraComponent.factory().create(
        EntryPointAccessors.fromApplication(
                requireActivity().applicationContext,
                CoreComponent::class.java
        ),
        requireActivity().application
)
        .inject(this)

The trick is here to get dependency interface annotated with @EntryPoint using EntryPointAccessors.fromApplication()

Also created Activity based dependencies in app module

MainActivityModule.kt

@InstallIn(ActivityComponent::class)
@Module(includes = [MainActivityBindModule::class])
class MainActivityModule {

    @Provides
    fun provideToastMaker(application: Application) = ToastMaker(application)

    @ActivityScoped@Provides
    fun provideMainActivityObject(context: Context) = MainActivityObject(context)

}

@InstallIn(ActivityComponent::class)
@Module
abstract class MainActivityBindModule {

    @Binds
    abstract fun bindContext(application: Application): Context

}

And only intend to inject these dependencies to Photos dynamic feature module so named it as PhotoDependencies

@EntryPoint@InstallIn(ActivityComponent::class)interfacePhotoModuleDependencies{

    funtoastMaker(): ToastMaker

    funmainActivityObject(): MainActivityObject
}

In Photos dynamic feature module create dagger module named PhotoModule

@InstallIn(FragmentComponent::class)
@Module(includes = [PhotoBindModule::class])
class PhotoModule {

    @Provides
    fun providePhotoObject(application: Application): PhotoObject = PhotoObject(application)

}

@InstallIn(FragmentComponent::class)
@Module
abstract class PhotoBindModule {
    @Binds
    abstract fun bindContext(application: Application): Context
}

And component

@Component(
        dependencies = [PhotoModuleDependencies::class],
        modules = [PhotoModule::class]
)interfacePhotoComponent{

    funinject(photosFragment1: PhotoFragment1)funinject(photosFragment2: PhotoFragment2)@Component.Factory
    interfaceFactory{
        funcreate(photoModuleDependencies: PhotoModuleDependencies,
                   @BindsInstance application: Application): PhotoComponent
    }
}

And inject to fragments with

DaggerPhotoComponent.factory().create(
        EntryPointAccessors.fromActivity(
                requireActivity(),
                PhotoModuleDependencies::class.java
        ),
        requireActivity().application
)
        .inject(this)

The trick here is to get EntryPointAccessors.fromActivity instead of fromApplication.

You can check out this link if you wish to experiment yourself.

If you wish to add ViewModel to dynamic feature modules with hilt you can check out my answer here.

Post a Comment for "Android Dynamic Feature Modules With Dagger Hilt"