Hilt code generation needs access to all the Gradle modules that use Hilt. The
Gradle module that compiles your
Application
class needs to have all Hilt
modules and constructor-injected classes in its transitive dependencies.
If your multi-module project is composed of regular Gradle modules, then you can use Hilt as described in Dependency injection with Hilt. However, this is not the case with apps that include feature modules.
Hilt in feature modules
In feature modules, the way that modules usually depend on each other is inverted. Therefore, Hilt cannot process annotations in feature modules. You must use Dagger to perform dependency injection in your feature modules.
You must use component dependencies to solve this problem with feature modules. Follow these steps:
- Declare an
@EntryPoint
interface in theapp
module (or in any other module that can be processed by Hilt) with the dependencies that the feature module needs. - Create a Dagger component that depends on the
@EntryPoint
interface. - Use Dagger as usual in the feature module.
Consider the example from the Dependency injection with
Hilt page. Suppose you add a
login
feature module to your project. You implement the login feature
with an activity called LoginActivity
. This means that you can get bindings
only from the application component.
For this feature, you need an OkHttpClient
with the authInterceptor
binding.
First, create an @EntryPoint
interface installed in the SingletonComponent
with the bindings that the login
module needs:
Kotlin
// LoginModuleDependencies.kt - File in the app module. @EntryPoint @InstallIn(SingletonComponent::class) interface LoginModuleDependencies { @AuthInterceptorOkHttpClient fun okHttpClient(): OkHttpClient }
Java
// LoginModuleDependencies.java - File in the app module. @EntryPoint @InstallIn(SingletonComponent.class) public interface LoginModuleDependencies { @AuthInterceptorOkHttpClient OkHttpClient okHttpClient(); }
To perform field injection in the LoginActivity
, create a Dagger
component that depends on the @EntryPoint
interface:
Kotlin
// LoginComponent.kt - File in the login module. @Component(dependencies = [LoginModuleDependencies::class]) interface LoginComponent { fun inject(activity: LoginActivity) @Component.Builder interface Builder { fun context(@BindsInstance context: Context): Builder fun appDependencies(loginModuleDependencies: LoginModuleDependencies): Builder fun build(): LoginComponent } }
Java
// LoginComponent.java - File in the login module. @Component(dependencies = LoginModuleDependencies.class) public interface LoginComponent { void inject(LoginActivity loginActivity); @Component.Builder interface Builder { Builder context(@BindsInstance Context context); Builder appDependencies(LoginModuleDependencies loginModuleDependencies); LoginComponent build(); } }
Once those steps are complete, use Dagger as usual in your feature module. For
example, you can use the bindings from the SingletonComponent
as a
dependency of a class:
Kotlin
// LoginAnalyticsAdapter.kt - File in the login module. class LoginAnalyticsAdapter @Inject constructor( @AuthInterceptorOkHttpClient okHttpClient: OkHttpClient ) { ... }
Java
// LoginAnalyticsAdapter.java - File in the login module. public class LoginAnalyticsAdapter { private final OkHttpClient okHttpClient; @Inject LoginAnalyticsAdapter( @AuthInterceptorOkHttpClient OkHttpClient okHttpClient ) { this.okHttpClient = okHttpClient; } ... }
To perform field injection, create an instance of the Dagger component
using the applicationContext
to get the SingletonComponent
dependencies:
Kotlin
// LoginActivity.kt - File in the login module. class LoginActivity : AppCompatActivity() { @Inject lateinit var loginAnalyticsAdapter: LoginAnalyticsAdapter override fun onCreate(savedInstanceState: Bundle?) { DaggerLoginComponent.builder() .context(this) .appDependencies( EntryPointAccessors.fromApplication( applicationContext, LoginModuleDependencies::class.java ) ) .build() .inject(this) super.onCreate(savedInstanceState) ... } }
Java
// LoginActivity.java - File in the login module. public class LoginActivity extends AppCompatActivity { @Inject LoginAnalyticsAdapter loginAnalyticsAdapter; @Override protected void onCreate(Bundle savedInstanceState) { DaggerLoginComponent.builder() .context(this) .appDependencies( EntryPointAccessors.fromApplication( getApplicationContext(), LoginModuleDependencies.class ) ) .build() .inject(this); super.onCreate(savedInstanceState); ... } }
For more context on module dependencies in feature modules, see Component dependencies with feature modules.
For more information about Dagger on Android, see Using Dagger in Android apps.