urbanairship / android-library

Urban Airship Android SDK
Other
109 stars 123 forks source link

AirshipWorker fails when app is using Work Manager with Custom Configuration #212

Closed vasilije15 closed 2 years ago

vasilije15 commented 2 years ago

❗For how-to inquiries involving Airship functionality or use cases, please contact (support)[https://support.airship.com/].

Preliminary Info

What Airship dependencies are you using?

FCM version 16.7.1

What are the versions of any relevant development tools you are using?

Android Studio Chipmunk 2021.2.1 Patch 2

Report

What unexpected behavior are you seeing?

Hello Urban Airship team.

In our app we recently introduced Work Manager. After injecting dependencies into our worker with the steps from these docs: https://developer.android.com/training/dependency-injection/hilt-jetpack#workmanager https://developer.android.com/topic/libraries/architecture/workmanager/advanced/custom-configuration we managed to setup Work Manager with Hilt.

However, our app kept crashing since it was calling takeOff() before shared(). After updating to latest version of Urban Airship SDK (16.7.1) and following the steps from this issue https://github.com/urbanairship/android-library/issues/202 we managed to fix the crash. However, now we noticed that AirshipWorker keeps failing in the background and thus we can't receive push notifications.

What is the expected behavior?

AirshipWorker should return success work and setup all the required background work to enable push notifications.

What are the steps to reproduce the unexpected behavior?

In your app, have a worker with custom configuration which uses @HiltWorker annotation like shown here: https://developer.android.com/reference/androidx/hilt/work/HiltWorker Add this to your manifest:

         <provider
            android:name="androidx.startup.InitializationProvider"
            tools:node="merge"
            android:authorities="${applicationId}.androidx-startup"
            android:exported="false">

            <meta-data
                android:name="androidx.work.WorkManagerInitializer"
                android:value="androidx.startup"
                tools:node="remove" />

            <meta-data
                android:name="com.urbanairship.AirshipInitializer"
                tools:node="remove" />

            <meta-data
                android:name="com.urbanairship.NoDependencyAirshipInitializer"
                android:value="androidx.startup" />
        </provider>

Your worker will work just fine, but AirshipWorker will keep failing shortly after app startup.

Do you have logging for the issue?

We keep seeing logs such as these com.urbanairship.job.AirshipWorker returned a Failure {mOutputData=Data {ERROR_MESSAGE : NO_INPUT_DATA, }} result. Worker result FAILURE for Work [ id=a8ce7f67-59f5-47f5-a069-8dcc6aaf916f, tags={ airship, com.urbanairship.job.AirshipWorker } ]

rlepinski commented 2 years ago

Could you share your work manager configuration?

vasilije15 commented 2 years ago

I am using work manager 2.7.1.

This is my application class:

@HiltAndroidApp
class MyApplication : BaseApplication(), Configuration.Provider {

    @Inject
    lateinit var myWorkerFactory: MyWorkerFactory

    override fun getWorkManagerConfiguration(): Configuration = Configuration.Builder().setMinimumLoggingLevel(android.util.Log.DEBUG)
        .setWorkerFactory(myWorkerFactory)
        .build()
}

I have a worker factory which is needed to inject dependencies:

class MyWorkerFactory @Inject constructor(
    private val dependency: Dependency
) : WorkerFactory() {

    override fun createWorker(appContext: Context, workerClassName: String, workerParameters: WorkerParameters): CoroutineWorker =
        MyWorker(appContext, workerParameters, dependency)
}

How my worker looks:

@HiltWorker
class MyWorker @AssistedInject constructor(
    @Assisted private val context: Context,
    @Assisted private val workerParameters: WorkerParameters,
    val dependency: Dependency
) : CoroutineWorker(context, workerParameters) {

    override suspend fun doWork(): Result {
        // do some work here
        return Result.success()
    }
}

In the manifest I added this in the application tag as mentioned here:

        <provider
            android:name="androidx.startup.InitializationProvider"
            tools:node="merge"
            android:authorities="${applicationId}.androidx-startup"
            android:exported="false">

            <meta-data
                android:name="androidx.work.WorkManagerInitializer"
                android:value="androidx.startup"
                tools:node="remove" />

            <meta-data
                android:name="com.urbanairship.AirshipInitializer"
                tools:node="remove" />

            <meta-data
                android:name="com.urbanairship.NoDependencyAirshipInitializer"
                android:value="androidx.startup" />
        </provider>

This is included in the manifest

        <meta-data
            android:name="com.urbanairship.autopilot"
            android:value="com.my.package.MyAutoPilot" />

and after running the app I can see that takeOff() happened as UALib: Airship taking off! is printed in the logs, however, as mentioned in the description AirshipWorker keeps failing.

jyaganeh commented 2 years ago

Hi @vasilije15, I think the issue here is that your WorkerFactory isn't able to create instances of AirshipWorker for jobs that our SDK needs to run. Could you try adding the following to see if it resolves your issue:

class MyWorkerFactory @Inject constructor(
    private val dependency: Dependency
) : WorkerFactory() {

    override fun createWorker(
        appContext: Context,
        workerClassName: String,
        workerParameters: WorkerParameters
    ): ListenableWorker =
        when (workerClassName) {
            "com.urbanairship.job.AirshipWorker" -> AirshipWorker(appContext, workerParameters)
            else -> MyWorker(appContext, workerParameters, dependency)
        }
}
caglacetin commented 2 years ago

Hi @jyaganeh,

"com.urbanairship.job.AirshipWorker" is not found despite adding required libraries. urbanairship-fcm 16.7.1 urbanairship-core 16.7.1

Thus, I cannot try this solution. Could you please correct me if I am missing something here? Thanks

rlepinski commented 2 years ago

@caglacetin The class is public and in the core module - https://github.com/urbanairship/android-library/blob/main/urbanairship-core/src/main/java/com/urbanairship/job/AirshipWorker.java

I am not sure why it would not be available to you. How are you pulling in Airship? Is it from another module? How is it defined in the build.gradle?

rlepinski commented 2 years ago

Going to close due to inactivity. Hopefully everything is resolved, if not please comment

vasilije15 commented 1 year ago

Hello again @rlepinski and sorry for a late reply. We had some problem in dependency setup. I tried what @jyaganeh suggested and it seems to have fixed the issue, both workers are now successful.

Thank you!

brillenheini commented 1 year ago

By the way, it is also possible to return null from createWorker, then the default factory will try to handle it

rlepinski commented 1 year ago

@brillenheini Thank you! That is good info.