Hilt em apps com vários módulos

A geração do código Hilt precisa acessar todos os módulos do Gradle que usam o Hilt. O módulo do Gradle que compila a classe Application precisa ter todos os módulos do Hilt e classes injetadas pelo construtor nas dependências transitivas dele.

Se o projeto de vários módulos for composto de módulos regulares do Gradle, use o Hilt conforme descrito em injeção de dependências com o Hilt. No entanto, esse não é o caso de apps que incluem módulos de recursos dinâmicos (DFMs, na sigla em inglês).

Hilt em módulos de recursos dinâmicos

Nos DFMs, a forma como os módulos geralmente dependem uns dos outros é invertida. Portanto, o Hilt não pode processar anotações em módulos de recursos dinâmicos. Use o Dagger para realizar a injeção de dependências nos seus DFMs.

É necessário usar dependências de componentes para resolver esse problema com DFMs. Siga estas etapas:

  1. Declare uma interface @EntryPoint no módulo app (ou em qualquer outro módulo que possa ser processado pelo Hilt) com as dependências necessárias ao DFM.
  2. Crie um componente Dagger que dependa da interface @EntryPoint.
  3. Use o Dagger como de costume no DFM.

Considere o exemplo da página Injeção de dependência com Hilt. Suponha que você adicione um módulo de recurso dinâmico login ao seu projeto. Você implementa o recurso de login com uma atividade chamada LoginActivity. Isso significa que você pode receber vinculações apenas do componente de aplicativo.

Para esse recurso, você precisa de um OkHttpClient com a vinculação authInterceptor.

Primeiro, crie uma interface @EntryPoint instalada no ApplicationComponent com as vinculações necessárias ao módulo login:

Kotlin

// LoginModuleDependencies.kt - File in the app module.

@EntryPoint
@InstallIn(ApplicationComponent::class)
interface LoginModuleDependencies {

  @AuthInterceptorOkHttpClient
  fun okHttpClient(): OkHttpClient
}

Java

// LoginModuleDependencies.java - File in the app module.

@EntryPoint
@InstallIn(ApplicationComponent.class)
public interface LoginModuleDependencies {

  @AuthInterceptorOkHttpClient
  OkHttpClient okHttpClient();
}

Para realizar a injeção de campo na LoginActivity, crie um componente Dagger que dependa da interface @EntryPoint:

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();
  }
}

Quando essas etapas forem concluídas, use o Dagger normalmente no seu DFM. Por exemplo, você pode usar as vinculações do ApplicationComponent como uma dependência de uma classe:

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;
  }
  ...
}

Para realizar a injeção de campo, crie uma instância do componente Dagger usando applicationContext para receber as dependências ApplicationComponent:

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(
          EntryPointsAccessors.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(
          EntryPointsAccessors.fromApplication(
            getApplicationContext(),
            LoginModuleDependencies.class
          )
        )
        .build()
        .inject(this);

    super.onCreate(savedInstanceState);
    ...
  }
}

Para mais contexto sobre dependências de módulos de recursos dinâmicos, consulte Dependências de componentes com módulos de recursos dinâmicos.

Para mais informações sobre o Dagger no Android, consulte Como usar o Dagger em apps para Android.