1

I am working on native Android app with Kotlin. I implement a Worker class to run async webservice call. My worker works fine unless I don't build with dexguard. With dexguard builds only I get following error

2021-12-07 18:16:46.085 25839-29600/? E/WM-WorkerFactory: Could not instantiate com.xyz.XYZWorker
    java.lang.NoSuchMethodException: com.xyz.XYZWorker.<init> [class android.content.Context, class androidx.work.WorkerParameters]
        at java.lang.Class.getConstructor0(Class.java:2332)
        at java.lang.Class.getDeclaredConstructor(Class.java:2170)
        at androidx.work.WorkerFactory.createWorkerWithDefaultFallback(:95)
        at androidx.work.impl.WorkerWrapper.runWorker(:244)
        at androidx.work.impl.WorkerWrapper.run(:136)
        at androidx.work.impl.utils.SerialExecutor$b.run(:91)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:923)

Here is my code, I mask some classnames because it is client project. I inject use cases with Hilt.

@HiltWorker
class XYZWorker @AssistedInject constructor(
    @Assisted context: Context,
    @Assisted workerParameters: WorkerParameters,
    val someUseCase: SomeUseCase,
    val someUseCase2: SomeUseCase2,
) : CoroutineWorker(context, workerParameters) {
...
}

Use cases provided by inject

class SomeUseCase @Inject constructor(
   private val someRepo: SomeRepo
) : UseCaseParams<List<SomeDomainEntity>, SomeResponseDomainEntity> {
   ...
}

class MyWorkManagerInitializer : Initializer<WorkManager> {

    override fun create(context: Context): WorkManager {
        val workerFactory = getWorkerFactory(appContext = context.applicationContext)
        val config = Configuration.Builder()
            .setWorkerFactory(workerFactory)
            .build()
        WorkManager.initialize(context, config)
        return WorkManager.getInstance(context)
    }

    override fun dependencies(): MutableList<Class<out Initializer<*>>> = mutableListOf()

    private fun getWorkerFactory(appContext: Context): HiltWorkerFactory {
        val workManagerEntryPoint = EntryPointAccessors.fromApplication(
            appContext,
            WorkManagerInitializerEntryPoint::class.java
        )
        return workManagerEntryPoint.hiltWorkerFactory()
    }

    @InstallIn(SingletonComponent::class)
    @EntryPoint
    interface WorkManagerInitializerEntryPoint {
        fun hiltWorkerFactory(): HiltWorkerFactory
    }
}

<provider
  android:name="androidx.work.impl.WorkManagerInitializer"
  android:authorities="${applicationId}.workmanager-init"
  android:exported="false"
  tools:node="remove" />

<provider
  android:name="androidx.startup.InitializationProvider"
  android:authorities="${applicationId}.androidx-startup"
  android:exported="false"
  tools:node="merge">
  <meta-data
    android:name="com.xyz.MyWorkManagerInitializer"
    android:value="@string/androidx_startup" />
</provider>

-keep public class androidx.startup.** { *; }
-keep public class androidx.work.** { *; }
-keep public class androidx.hilt.work.** { *; }

-keep @interface androidx.hilt.work.** { *; }
-keep @interface dagger.assisted.** { *; }
-keep @interface dagger.assisted.** { *; }

-keep public class * implements androidx.startup.Initializer { *; }

-keep interface com.xyz.WorkManagerInitializerEntryPoint { *; }
-keep public class * implements com.xyz.WorkManagerInitializerEntryPoint { *; }

-keep public class * extends androidx.work.CoroutineWorker { *; }
-keepclassmembers public class * extends androidx.work.CoroutineWorker {
    public <init>(...);
    @com.google.inject.Inject <init>(...);
    @javax.inject.Inject <init>(...);
}

-keep public class * extends androidx.work.Worker { *; }
-keepclassmembers public class * extends androidx.work.Worker {
    public <init>(...);
    @com.google.inject.Inject <init>(...);
    @javax.inject.Inject <init>(...);
}

-keep public class com.xyz.SomeUseCase { *; }
-keep public class com.xyz.SomeUseCase2 { *; }

and here is my libraries

implementation androidx.hilt:hilt-work:1.0.0-alpha03
implementation androidx.work:work-runtime-ktx:2.5.0
kapt androidx.hilt:hilt-compiler:1.0.0-alpha03
bkaancelen
  • 163
  • 2
  • 11
  • Are you using [WorkManager 2.6.0](https://developer.android.com/jetpack/androidx/releases/work#2.6.0) or higher? That code to remove the `WorkManagerInitializer` would only apply to earlier versions of WorkManager. – ianhanniballake Dec 07 '21 at 16:22
  • @ianhanniballake how is this solvable, then? I do not have anything `WorkManager` related in the manifest or the `Application` class, I do not use `Hilt` (or `Dagger`) but I am still getting the same error with version `2.7.1` when running debug version. All the solutions so far are about `Hilt`. Is this worthy of a new question? – Primož Ivančič Dec 21 '21 at 23:30
  • @PrimožIvančič - my comment was trying to understand what the `tools:node="remove"` code of a `WorkManagerInitializer` that doesn't even exist in WorkManager 2.6.0 or higher is trying to do. You'd need to follow the docs I linked to actually remove the default initializer correctly in WorkManager 2.6+. But the original poster didn't say what version of WorkManager they were using. – ianhanniballake Dec 21 '21 at 23:56

0 Answers0