Dagger est un framework d'injection de dépendances pour Java et Kotlin qui génère du code DI à la compilation via le traitement d'annotations. Hilt est une surcouche de Dagger pour Android qui simplifie la configuration des composants et la gestion du cycle de vie. Selon Google, 2025, Hilt est utilisé dans plus de 70 % des applications Android du Top-100 Google Play, prenant en charge Activity, Fragment, ViewModel et Service via des composants prédéfinis. Les deux frameworks assurent la vérification du graphe de dépendances à la compilation, éliminant les erreurs d'injection à l'exécution.
Points clés
Dagger est un framework d'injection de dépendances avec génération de code à la compilation. Développé initialement chez Square puis transféré à Google, Dagger utilise le processeur d'annotations Java APT pour analyser le graphe de dépendances et générer des classes factory. Contrairement au DI à l'exécution (Guice, Koin), Dagger n'utilise pas la réflexion — tout le code est créé à la compilation, garantissant des performances d'exécution maximales et la détection des erreurs à la construction.
Hilt est une bibliothèque Google construite sur Dagger et optimisée pour Android. Hilt fournit des composants prédéfinis correspondant au cycle de vie des composants Android : @SingletonComponent pour Application, @ActivityComponent pour Activity, @FragmentComponent pour Fragment, @ViewModelComponent pour ViewModel. Cela élimine la configuration routinière de Component et Module requise dans Dagger pur. Hilt génère également automatiquement le graphe de dépendances pour chaque composant Android via @AndroidEntryPoint.
Selon Google I/O 2024, Hilt est la solution recommandée pour DI dans les applications Android écrites en Kotlin. Les bibliothèques Jetpack (Navigation, Room, WorkManager) ont une intégration intégrée avec Hilt via @HiltViewModel et @HiltWorker. Dans les projets n'utilisant pas Android (bibliothèques Java/Kotlin pures, applications serveur), Dagger pur est utilisé sans la surcouche Hilt.
Sans framework DI, le développeur crée des objets manuellement via des constructeurs ou des fabriques, en transmettant les dépendances le long de la chaîne. Chaque nouvelle exigence signifie modifier les signatures de tous les constructeurs de la chaîne. Dagger automatise ce processus : il suffit de déclarer le type requis (@Inject constructor), et Dagger crée le graphe de dépendances, résolvant tous les types imbriqués. Lorsque les dépendances changent, Dagger met à jour automatiquement le code généré — il est impossible de se tromper dans la chaîne.
L'injection de dépendances est un modèle dans lequel un objet reçoit ses dépendances de l'extérieur plutôt que de les créer lui-même. DI implémente le principe d'inversion de contrôle (IoC) : une classe n'est pas responsable de la création de ses propres dépendances, mais les déclare via un constructeur, une méthode ou un champ. L'injection par constructeur est considérée comme la plus préférable car elle garantit que l'objet est créé dans un état valide.
| Type d'injection | Syntaxe Dagger | Quand l'utiliser |
|---|---|---|
| Constructor injection | @Inject constructor | Méthode principale — pour toutes les classes personnalisées |
| Field injection | @Inject lateinit var | Uniquement pour les composants Android (Activity, Fragment) |
| Method injection | @Inject fun bind() | Pour l'initialisation post-construction |
Les principaux avantages du DI incluent la testabilité (les dépendances peuvent être remplacées par des objets mock), le faible couplage (les classes dépendent d'interfaces, pas d'implémentations) et la gestion explicite du cycle de vie des objets via des scopes. Dagger garantit automatiquement qu'un objet est créé une fois dans son scope et détruit à la sortie du scope.
Component est l'élément central du graphe de dépendances de Dagger. C'est une interface annotée avec @Component qui décrit le pont entre Module et les cibles d'injection. Dagger génère l'implémentation de Component (par exemple DaggerAppComponent) à la compilation. Le Component détermine quels types sont disponibles pour l'injection via des méthodes abstraites retournant les types requis ou via des méthodes inject acceptant un objet pour l'injection de champ.
// Module : fournit les dépendances que Dagger ne peut pas créer lui-même
@Module
class NetworkModule {
@Provides
@Singleton
fun provideOkHttpClient(): OkHttpClient {
return OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.build()
}
@Provides
@Singleton
fun provideApiService(client: OkHttpClient): ApiService {
return Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ApiService::class.java)
}
}
// Component : relie Module et les cibles d'injection
@Component(modules = [NetworkModule::class])
interface AppComponent {
fun inject(activity: MainActivity)
fun getApiService(): ApiService
}
@Module est une classe contenant des méthodes avec @Provides qui retournent des instances de dépendances. Module est utilisé pour les types que Dagger ne peut pas créer automatiquement : bibliothèques tierces (OkHttp, Retrofit), objets avec paramètres de constructeur, interfaces avec sélection d'implémentation. @Binds est une alternative à @Provides pour les cas où une méthode retourne une interface et accepte une seule implémentation : Dagger génère un cast direct sans appeler la méthode.
@Scope définit la durée de vie d'un objet dans le graphe de dépendances. @Singleton — l'objet est créé une fois pour toute l'application. @ActivityScoped — l'objet vit tant que l'Activity vit. @FragmentScoped — tant que le Fragment vit. Sans scope, Dagger crée une nouvelle instance à chaque injection. @Reusable — un scope pour les objets qui ne doivent pas être des singletons mais dont la création est coûteuse — Dagger peut mettre en cache l'instance mais ne le garantit pas.
Hilt simplifie la configuration de Dagger pour Android grâce à des composants prédéfinis et à la génération automatique du graphe de base. L'annotation @HiltAndroidApp sur la classe Application déclenche la génération du composant Hilt. Sans cette annotation, Hilt ne fonctionne pas — elle est obligatoire pour toute application Android utilisant Hilt. @HiltAndroidApp crée le composant parent SingletonComponent, dont héritent tous les autres composants de l'application.
@HiltAndroidApp
class MyApplication : Application()
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject lateinit var apiService: ApiService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// apiService déjà injecté avant l'appel à onCreate
}
}
@Module
@InstallIn(SingletonComponent::class)
class AppModule {
@Provides
@Singleton
fun provideDatabase(@ApplicationContext ctx: Context): AppDatabase {
return Room.databaseBuilder(ctx, AppDatabase::class.java, "app.db").build()
}
}
@AndroidEntryPoint est une annotation pour Activity, Fragment, Service, BroadcastReceiver et View. Elle génère un composant Hilt pour chaque type : @AndroidEntryPoint sur une Activity crée un ActivityComponent qui hérite de SingletonComponent. Le composant enfant reçoit automatiquement toutes les dépendances du parent. L'injection de champ avec @Inject lateinit var n'est disponible que dans les classes annotées avec @AndroidEntryPoint — dans les classes normales, l'injection par constructeur est utilisée.
@InstallIn spécifie dans quel composant Hilt un module est installé. NetworkModule avec @InstallIn(SingletonComponent::class) est disponible dans toute l'application. Un Module avec @InstallIn(ActivityComponent::class) n'est disponible que dans Activity. Cela isole les graphes de dépendances : les modules spécifiques à Activity ne sont pas visibles dans Fragment et ViewModel, empêchant l'utilisation accidentelle de dépendances invalides. @ApplicationContext est un qualificateur intégré de Hilt pour obtenir le Context de l'application.
Lorsque deux implémentations différentes de la même interface doivent être injectées, des qualificateurs sont utilisés. Hilt prend en charge @Named pour les identifiants de chaîne et les annotations personnalisées avec @Qualifier. Par exemple, @Named("baseUrl") et @Named("imageBaseUrl") pour différentes configurations de chaîne. Les qualificateurs personnalisés sont préférables à @Named en raison de la vérification à la compilation — un nom de chaîne incorrect ne sera détecté qu'à l'exécution.
@HiltViewModel est une annotation qui remplace la fabrique manuelle ViewModelProvider.Factory. Une classe annotée avec @HiltViewModel avec @Inject constructor reçoit automatiquement toutes les dépendances via Dagger. Hilt génère une ViewModelFactory utilisée par Jetpack ViewModelProvider. Sans Hilt, le développeur doit écrire la fabrique manuellement, en passant chaque paramètre depuis l'Activity ou le fragment.
@HiltViewModel
class MainViewModel
@Inject constructor(
private val apiService: ApiService,
private val database: AppDatabase
) : ViewModel() {
private val _users = MutableStateFlow<List<User>>(emptyList())
val users: StateFlow<List<User>> = _users.asStateFlow()
fun loadUsers() {
viewModelScope.launch {
_users.value = apiService.getUsers()
}
}
}
// Dans Activity — Hilt crée automatiquement le ViewModel
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
}
ViewModelScoped est un scope Hilt pour les dépendances qui vivent tant que le ViewModel vit. Si deux ViewModels du même type injectent la même dépendance @ViewModelScoped, chacun reçoit sa propre instance. Cela distingue @ViewModelScoped de @ActivityScoped, où une Activity reçoit une instance pour tous les fragments. Pour les dépendances spécifiques à ViewModel (par exemple SavedStateHandle), @HiltViewModel est utilisé avec @Inject constructor(savedStateHandle: SavedStateHandle).
Hilt prend en charge l'injection assistée via la bibliothèque Hilt Extensions. L'injection assistée permet de passer des paramètres au constructeur au moment de l'injection lorsque certaines dépendances ne sont connues qu'à l'exécution (par exemple, l'ID utilisateur d'une intention). Pour l'injection assistée, @AssistedInject est utilisé en combinaison avec des paramètres @Assisted. Hilt génère une AssistedFactory qui peut être injectée de manière standard.
Dagger pur nécessite la création manuelle de Component, la définition de scopes et la configuration de l'injection dans chaque composant Android. Le développeur crée AppComponent, ActivityComponent, FragmentComponent et gère leurs relations via @Subcomponent. Cette approche offre un contrôle maximal mais nécessite une quantité importante de code passe-partout. Dagger est utilisé dans les grands projets nécessitant une architecture DI non standard, ou dans les projets Java/Kotlin non Android.
Hilt automatise le code passe-partout : un @HiltAndroidApp, un @AndroidEntryPoint pour chaque composant, des scopes prédéfinis. Google recommande Hilt pour tous les nouveaux projets Android. La migration de Dagger vers Hilt inclut le remplacement de Component par @InstallIn, le remplacement de @Subcomponent par des composants Hilt prédéfinis et le remplacement de la fabrique manuelle ViewModelProvider.Factory par @HiltViewModel. La plupart des classes @Module sont migrées avec l'ajout de @InstallIn sans modifier les méthodes @Provides.
| Caractéristique | Dagger | Hilt |
|---|---|---|
| Configuration | Manuelle : Component, Subcomponent, Builder | Automatique : @HiltAndroidApp, @AndroidEntryPoint |
| Composants Android | Aucun prédéfini | 12+ composants intégrés |
| ViewModel | Fabrique manuelle | @HiltViewModel + @Inject constructor |
| Multimodule | Via @Component(dependencies) | Via @InstallIn + agrégation |
| Complexité | Élevée — expérience requise | Faible — intuitivement compréhensible |
| Flexibilité | Maximale | Standard (couvre 95 % des scénarios) |
Limitations de Hilt : la bibliothèque ne prend en charge qu'Android (inadaptée aux projets Java purement serveur), impose une certaine structure de composants (difficile à redéfinir) et ajoute une dépendance à android.hilt:hilt-navigation-compose pour les projets Jetpack Compose. Pour les applications Compose, Hilt fournit @HiltViewModel accessible dans Composable via hiltViewModel() — sans fourniture manuelle de ViewModel depuis Activity.
Questions fréquentes
Dagger est un framework DI de base à la compilation avec configuration manuelle de Component et Module. Hilt est une surcouche Android qui automatise la création de composants et l'intégration avec le cycle de vie d'Activity, Fragment, ViewModel, Service et BroadcastReceiver.
@HiltAndroidApp active la génération du composant Hilt pour Application. Sans cette annotation, Hilt ne peut pas créer le SingletonComponent de base dont héritent tous les ActivityComponent, FragmentComponent et ViewModelComponent. L'annotation est obligatoire pour tout projet Hilt.
Hilt Navigation fournit @HiltViewModel pour ViewModel dans NavBackStackEntry et hiltNavGraphViewModels() pour le scoping de ViewModel dans le graphe de navigation. La bibliothèque android.hilt:hilt-navigation-fragment crée automatiquement un ViewModel pour chaque NavBackStackEntry.
Utilisez @ApplicationContext pour le contexte d'application ou @ActivityContext pour le contexte d'Activity. Hilt fournit ces qualificateurs intégrés dans la bibliothèque android.hilt:hilt-android. @ActivityContext n'est disponible que dans les modules installés dans ActivityComponent.
@Binds est une alternative efficace à @Provides lorsqu'une méthode accepte exactement un paramètre et retourne son type comme interface. @Binds génère un cast direct sans appeler la méthode, réduisant la quantité de code généré et améliorant les performances d'injection.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi