Hilt em apps com vários módulos

A geração de código do 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 as 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 com apps que incluem módulos de recursos.

Hilt em módulos de recursos

Nos módulos de recursos, 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. Você precisa usar o Dagger para realizar a injeção de dependências nos módulos de recursos.

Use dependências de componentes para resolver esse problema com módulos de recursos. 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 módulo de recurso.
  2. Crie um componente Dagger que dependa da interface @EntryPoint.
  3. Use o Dagger normalmente no módulo de recurso.

Considere o exemplo da página Injeção de dependências com o Hilt. Se você adicionar um módulo de recurso login ao projeto, vai precisar implementar 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 SingletonComponent com as vinculações necessárias ao módulo login:

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

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 como de costume no módulo de recurso. Por exemplo, você pode usar as vinculações do SingletonComponent como uma dependência de 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 SingletonComponent:

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

Para ver mais contexto sobre dependências de módulos em módulos de recursos, consulte Dependências de componentes com módulos de recursos.

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