wire.hilt) applies the Hilt plugin, KSP, and the required dependencies to any module
that needs them.
Hilt component hierarchy
Hilt’s standard Android component tree maps directly onto Wire’s scoping strategy:Application-scoped modules
Modules installed inSingletonComponent are created once for the lifetime of
the process.
AppModule
app/di/AppModule.kt — installed in SingletonComponent.
Provides Android framework singletons and app-wide utilities:
| Binding | Type |
|---|---|
Context | ApplicationContext |
DispatcherProvider | DefaultDispatcherProvider |
UiTextResolver | AndroidUiTextResolver |
NotificationManager / NotificationManagerCompat | System services |
AudioManager | System service |
CurrentTimestampProvider | () -> Long |
AnalyticsConfiguration | Enabled or Disabled based on BuildConfig.ANALYTICS_ENABLED |
AnonymousAnalyticsManager | Singleton analytics manager |
MessageSharedState | Shared state for message composition |
CoreLogicModule
app/di/CoreLogicModule.kt — the bridge between Hilt and Kalium.
CoreLogic is the single entry point into Kalium. Every use case is obtained
from it — never instantiated directly. The @KaliumCoreLogic qualifier
distinguishes it from other CoreLogic-shaped objects that might exist in tests.
CoreLogicModule also exposes global (session-independent) use cases directly
into the graph:
Account-scoped (ViewModelScoped) modules
Use cases that operate on a specific user account are scoped toViewModelComponent using @ViewModelScoped. This scope is tied to the
lifetime of a single ViewModel — it is created when the ViewModel is created
and destroyed when the ViewModel is cleared.
How the current account is resolved
SessionModule (also in CoreLogicModule.kt) resolves the active UserId at
ViewModel creation time:
@CurrentAccount UserId to call
coreLogic.getSessionScope(currentAccount) and extract the relevant use case:
@ViewModelScoped means the resolved UserId — and every use case derived
from it — is cached for the lifetime of the ViewModel. If the active account
changes, the ViewModel (and its scope) is recreated, picking up the new
session automatically.accountScoped/ modules
Theapp/di/accountScoped/ directory contains one Hilt module per domain area.
Each module is installed in ViewModelComponent and follows the same pattern:
resolve a Kalium scope object, then expose individual use cases from it.
ConversationModule
Provides all conversation use cases: observe list, create group/channel,
add/remove members, update muted status, manage legal hold, folders, etc.
Derives use cases from
ConversationScope.CallsModule
Provides call lifecycle use cases: start/end call, mute/unmute, video
controls, speaker toggling, observe incoming/ongoing calls.
Derives use cases from
CallsScope.MessageModule
Provides message sending, deletion, reactions, read receipts, and asset
upload use cases.
AuthenticationModule
Provides authentication use cases scoped to the current account (e.g.
credential refresh, E2EI certificate management).
UserModule
Provides self-user and other-user observation, handle/display-name updates,
avatar management.
ClientModule
Provides device/client registration and management use cases.
BackupModule
Provides multi-platform backup creation and restoration use cases.
CellsModule
Provides Wire Cells (file storage) use cases for the current account.
ChannelsModule, ConnectionModule, DebugModule, SearchModule,
ServicesModule, TeamModule.
Example: ConversationModule pattern
Service-scoped dependencies
ServiceModule (in CoreLogicModule.kt) provides dependencies scoped to
Android Service components — specifically the persistent WebSocket service:
Qualifier annotations
Several custom@Qualifier annotations prevent ambiguous injection:
| Qualifier | Purpose |
|---|---|
@KaliumCoreLogic | Disambiguates the production CoreLogic from test doubles |
@CurrentAccount | Marks the UserId of the currently active session |
@CurrentSessionFlowService | Session flow use case when injected into a Service |
@NoSession | QualifiedIdMapper that works without an active session |
@DefaultWebSocketEnabledByDefault | Boolean flag for WebSocket default state |
@CurrentAppVersion | Int holding BuildConfig.VERSION_CODE |
ViewModelScoped utilities
app/di/ViewModelScoped.kt provides helpers for sub-screen ViewModels that
survive recomposition using the Resaca
library:
ScopedArgs is a marker interface that provides a key property used to
cache separate ViewModel instances per unique argument set. This is how
ConversationListViewModel maintains independent state for each
ConversationsSource (all conversations, archive, search) displayed within
the same screen hierarchy.
KSP and the Hilt convention plugin
Thewire.hilt convention plugin (build-logic/plugins/HiltConventionPlugin.kt)
standardises Hilt adoption across modules:
build.gradle.kts is all that is needed to
enable Hilt and KSP-based code generation in that module: