Hilt en apps con varios módulos

Para generar códigos, Hilt necesita acceso a todos los módulos de Gradle que usan Hilt. El módulo de Gradle que compila tu clase Application debe tener todos los módulos y las clases insertadas por constructor de Hilt en sus dependencias transitivas.

Si tu proyecto de varios módulos está compuesto por módulos de Gradle normales, puedes usar Hilt como se describe en Inserción de dependencias con Hilt. Sin embargo, este no es el caso de las apps que incluyen módulos de funciones.

Hilt en módulos de funciones

En los módulos de funciones, se invierte la forma en que los módulos suelen depender unos de otros. Por lo tanto, Hilt no puede procesar anotaciones en los módulos de funciones. Debes usar Dagger para realizar la inserción de dependencias en tus módulos de funciones.

Debes usar dependencias de componentes para resolver este problema con los módulos de funciones. Sigue estos pasos:

  1. Declara una interfaz @EntryPoint en el módulo app (o en cualquier otro módulo que Hilt pueda procesar) con las dependencias que necesite el módulo de funciones.
  2. Crea un componente de Dagger que dependa de la interfaz @EntryPoint.
  3. Usa Dagger como de costumbre en el módulo de funciones.

Considera el ejemplo de la página Inserción de dependencias con Hilt. Supongamos que agregas un módulo de funciones login a tu proyecto. Implementas la función de acceso con una actividad llamada LoginActivity. Esto quiere decir que solo puedes obtener vinculaciones desde el componente de la aplicación.

Para esta función, necesitas un objeto OkHttpClient con la vinculación authInterceptor.

Primero, crea una interfaz @EntryPoint instalada en el SingletonComponent con las vinculaciones que necesita el 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 la inyección de campo en la LoginActivity, crea un componente de Dagger que dependa de la interfaz @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();
  }
}

Una vez que completes esos pasos, usa Dagger como de costumbre en tu módulo de funciones. Por ejemplo, puedes usar las vinculaciones de SingletonComponent como dependencia de una clase:

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

A fin de realizar la inyección de campo, crea una instancia del componente de Dagger usando el applicationContext para obtener las dependencias de 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 obtener más información sobre las dependencias de módulos en módulos de funciones, consulta Dependencias de componentes con módulos de funciones.

Para obtener más información sobre Dagger en Android, consulta Cómo usar Dagger en apps para Android.