Существуют 2 способа связи компонентов в Dagger: Subcomponents и Component Dependencies и каждый из них имеет свои преимущества.
Например, при использовании подхода Subcomponents весь код генерируется в :app модуле и это может привести к ошибке компиляции вроде “cannot access SomeClass” из-за транзитивной зависимости на этот класс. Component dependencies может быть использован для решения такой проблемы. Подробнее об этом можно прочитать в статье Lock your Dagger in Gradle Modules.
Hilt базируется на подходе subcomponents и описание этих компонентов скрыто от нас, поэтому мы не можем добавить зависимость на внешний компонент. Давайте посмотрим, как это можно обойти.
Предположим, у нас есть 2 gradle модуля :app -> :feature и есть независимый dagger component в :feature модуле (здесь только чистый Dagger, нет плагина и зависимостей для Hilt) который мы хотим добавить как component dependency в иерархию компонентов Hilt.
// :feature module
@Singleton
@Component
interface SomeFeatureComponent {
fun someFeature(): SomeFeature
}
Для этого можно создать «proxy» Hilt модуль, который будет хранить в себе внешний компонент и предоставлять зависимости в граф Hilt. Теперь `someFeature` из внешнего dagger component’а может быть инжектирована через Hilt везде, где вам потребуется в :app модуле.
// :app module
@Module
@InstallIn(SingletonComponent::class)
internal class SomeFeatureProxyModule {
// Pass as method args any dependencies from :app you need to build component
@Singleton
@Provides
fun someFeatureComponent(application: Application): SomeFeatureComponent {
return DaggerSomeFeatureComponent.builder().build()
}
// Use someFeature in Hilt
@Provides
fun someFeature(someFeatureComponent: SomeFeatureComponent): SomeFeature {
return someFeatureComponent.someFeature()
}
}
Стоит заметить, что это решение работает не только для Hilt, но для и подхода через subcomponents в целом. Когда вы не используете Hilt и вручную описываете граф, вы можете определить зависимости только для корневого компонента, аннотированного @Component, но для любого дочернего компонента, аннотированного @Subcomponent такой возможности уже нет. Тем не менее, можно добавить @Module к @Subcoponent и использовать описанный обходной путь.
Исходный код доступен на GitHub