Hilt в многомодульных приложениях

Для генерации кода Hilt требуется доступ ко всем модулям Gradle, использующим Hilt. Модуль Gradle, который компилирует класс Application, должен содержать все модули Hilt и классы, внедренные через конструктор, в своих транзитивных зависимостях.

Если ваш многомодульный проект состоит из обычных модулей Gradle, вы можете использовать Hilt, как описано в статье Внедрение зависимостей с помощью Hilt. Однако это не относится к приложениям, в которых есть модули функций.

Hilt в модулях функций

В модулях функций зависимость модулей друг от друга обычно инвертирована. Поэтому Hilt не может обрабатывать аннотации в модулях функций. Для внедрения зависимостей в модулях функций необходимо использовать Dagger.

Чтобы решить эту проблему с модулями функций, необходимо использовать зависимости компонентов. Выполните следующие действия:

  1. Объявите интерфейс @EntryPoint в модуле app (или в любом другом модуле, который может быть обработан Hilt) с зависимостями, необходимыми модулю функции.
  2. Создайте компонент Dagger, который зависит от интерфейса @EntryPoint.
  3. Используйте Dagger в модуле функции как обычно.

Рассмотрим пример со страницы Внедрение зависимостей с помощью Hilt. Предположим, вы добавили в проект модуль функции login. Вы реализуете функцию входа с помощью действия LoginActivity. Это означает, что вы можете получить привязки только из компонента приложения.

Для этой функции требуется OkHttpClient с привязкой authInterceptor.

Сначала создайте интерфейс @EntryPoint, установленный в SingletonComponent, с привязками, которые нужны модулю 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();
}

Чтобы выполнить внедрение через поле в LoginActivity, создайте компонент Dagger, который зависит от интерфейса @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();
  }
}

После выполнения этих шагов используйте Dagger в модуле функции как обычно. Например, вы можете использовать привязки из SingletonComponent в качестве зависимости класса:

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

Чтобы выполнить внедрение через поле, создайте экземпляр компонента Dagger с помощью applicationContext, чтобы получить зависимости 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);
    ...
  }
}

Дополнительную информацию о зависимостях компонентов в модулях функций можно найти в этой статье.

Подробнее об использовании Dagger в приложениях для Android…