androidandroid-jetpackdagger-hilt

How to use Hilt DI with WorkerManager in Android?


I want to use a Worker in my Android app (pure Kotlin) to so some background work. I'm using Hilt for dependency injection, but I'm facing some problems when I need to pass a custom object to the Worker.

My code is as follows:

@HiltWorker
class BackgroundWorker @AssistedInject constructor(
    @Assisted appContext: Context,
    @Assisted workerParams: WorkerParameters,
    val mockClass: MockClass
) : CoroutineWorker(appContext, workerParams) {

    init {
        Log.d("deb", "Worker: Initiated")
    }
    
    override suspend fun doWork(): Result {
        Log.d("deb", "Worker: Doing work!")
        return Result.success()
    }
}

And my MockClass is:

@Module
@InstallIn(SingletonComponent::class)
object MockModule {
    @Singleton
    @Provides
    fun provideMockClass(): MockClass = MockClass()
}

class MockClass{}

Inside my onCreate function in my main activity I call:

 WorkManager.getInstance(applicationContext).enqueue(
            OneTimeWorkRequestBuilder<BackgroundWorker>().build()
        )

to initiate the worker and call de doWork function, but when I start the app, I don't see the logs and the AppInspector shows "Failed" as the WorkerStatus.

I know that my Application class (annotated with @HiltAndroidApp) is correctly configured (using WorkerFactory, etc.) and the AndroidManifest.xml is well configured (using the provider tag, etc.), because when I comment out the line:

    val mockClass: MockClass

then I see the logs from inside my Worker (both of them, the init and the doWork one). So it works perfectly fine! But when I uncomment the line (so that the mockClass object is passed to the worker), the worker is not able to initiate.

Just for completion, here is my Manifest:

<application
    ...
    android:name=".MyApplication">
    <provider
        android:name="androidx.startup.InitializationProvider"
        android:authorities="${applicationId}.androidx-startup"
        tools:node="remove">
    </provider>
    ...
</>

, Application class:

@HiltAndroidApp
class MyApplication : Application(), Configuration.Provider {
    @Inject
    lateinit var workerFactory: HiltWorkerFactory

    override val workManagerConfiguration: Configuration
        get() = Configuration.Builder()
            .setWorkerFactory(workerFactory)
            .build()
}

, the dependencies I'm using:

[verions]
hiltCommon = "1.2.0"
workerRuntimeKtx = "2.10.0"
hilt = "2.55"
hilt-work = "1.2.0"
kotlin = "2.1.0"
ksp = "2.1.0-1.0.29"

[libraries]
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" }
hilt-work = { group = "androidx.hilt", name = "hilt-work", version.ref = "hilt-work" }
androidx-hilt-common = { group = "androidx.hilt", name = "hilt-common", version.ref = "hiltCommon" }
androidx-worker-runtime-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "workerRuntimeKtx" }

[plugins]
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
kotlin-ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }

in module-level build.gradle:

plugins{
    ...
    alias(libs.plugins.hilt)
    alias(libs.plugins.kotlin.ksp)
}
dependencies{
    implementation(libs.androidx.worker.runtime.ktx)
    implementation(libs.hilt.android)
    implementation(libs.hilt.work)
    implementation(libs.androidx.hilt.common)
    ksp(libs.hilt.compiler){
        exclude("META-INF/gradle/incremental.annotation.processors")
    }
}

and in project-level build.gradle:

plugins{
    alias(libs.plugins.kotlin.ksp) apply false
    alias(libs.plugins.hilt) apply false
}

I think my problem is somehow related to the DI and Hilt, but I cannot figure out what it is. I use Hilt for dependency injection on other parts in my app, and they work okay.


Solution

  • Your Gradle setup for Hilt is off.

    In your version catalog you need to replace the two libraries

    hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" }
    androidx-hilt-common = { group = "androidx.hilt", name = "hilt-common", version.ref = "hiltCommon" }
    

    with these:

    hilt-android-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
    androidx-hilt-compiler = { group = "androidx.hilt", name = "hilt-compiler", version.ref = "hilt-work" }
    

    Now, in your gradle file replace

    implementation(libs.androidx.hilt.common)
    ksp(libs.hilt.compiler){
        exclude("META-INF/gradle/incremental.annotation.processors")
    }
    

    accordingly with

    ksp(libs.hilt.android.compiler)
    ksp(libs.androidx.hilt.compiler)
    

    The Hilt injection should now work without issues, even for the WorkManager.