Closed barry-irvine closed 1 year ago
This looks like a similar issue to this - https://github.com/urbanairship/android-library/issues/212, you might need to provide your own factory and return null for default for Airships worker ID
I tried this based on the other issue but I'm still getting the same error (although the line numbers have moved because the change in implementation:
open class BaseApplication : Application(), Configuration.Provider {
override fun getWorkManagerConfiguration(): Configuration {
return Configuration.Builder().setWorkerFactory(
CustomWorkerFactory(
EntryPoints.get(this, WorkerFactoryEntryPoint::class.java).workerFactory
)
).build()
}
class CustomWorkerFactory(private val hiltWorkerFactory: HiltWorkerFactory) : WorkerFactory() {
override fun createWorker(
appContext: Context,
workerClassName: String,
workerParameters: WorkerParameters
): ListenableWorker? {
return when (workerClassName) {
"com.urbanairship.job.AirshipWorker" -> AirshipWorker(appContext, workerParameters)
else -> hiltWorkerFactory.createWorker(
appContext,
workerClassName,
workerParameters
)
}
}
}
@EntryPoint
@InstallIn(SingletonComponent::class)
interface WorkerFactoryEntryPoint {
val workerFactory: HiltWorkerFactory
}
}
Hi @barry-irvine, from the stack trace, it doesn't look like this is being caused by the Airship SDK:
Caused by: java.lang.IllegalStateException: The component was not created. Check that you have added the HiltAndroidRule.
I believe you also may need to use EarlyEntryPoint
instead of the normal EntryPoint
when installing/getting the worker factory, since SingletonComponent
is created after Application.onCreate()
is called in instrumentation tests (ref).
Would you be able to provide an example of one of your tests, with rules/setup?
Hi @jyaganeh
I tried changing the original Base Application to use EarlyEntryPoint but still no dice. All our tests use a base test class which looks like this:
open class BaseTest {
@get:Rule(order = 0)
val disableAnimationsRule = DisableAnimationsRule()
@get:Rule(order = 1)
val hiltRule by lazy { HiltAndroidRule(this) }
@get:Rule(order = 2)
val composeTestRule = createAndroidComposeRule<MainActivity>()
@Inject
lateinit var skipOnboarding: SkipOnboarding
@Inject
lateinit var languagePref: LanguagePref
@Inject
lateinit var workManager: WorkManager
private val mockWebServer = GoCityMockWebServer()
open var shouldSkipOnboarding = true
@Before
open fun setUp() {
hiltRule.inject()
if (shouldSkipOnboarding) {
skipOnboarding()
} else {
runTest { languagePref.setLanguage(Locale.US) }
}
mockWebServer.start()
mockWebServer.setupDefaultMocks()
composeTestRule.waitForIdle()
}
@After
open fun teardown() {
mockWebServer.shutdown()
workManager.cancelAllWork()
}
}
@jyaganeh Oops sorry. I missed the EarlyEntryPoints.get()
aspect!
Thank you so much. The only error that I see in the logs now is:
AirshipChannel - Channel registration failed, will retry
com.urbanairship.http.RequestException: Unable to perform request: missing URL
For reference my BaseApplication now looks like this:
open class BaseApplication : Application(), Configuration.Provider {
override fun getWorkManagerConfiguration(): Configuration {
return Configuration.Builder().setWorkerFactory(EarlyEntryPoints.get(applicationContext, WorkerFactoryEntryPoint::class.java).workerFactory).build()
}
@EarlyEntryPoint
@InstallIn(SingletonComponent::class)
interface WorkerFactoryEntryPoint {
val workerFactory: HiltWorkerFactory
}
}
That is an expected error message right now. Ill see if we can suppress for the 16.9 release.
The error should no longer be logged in 16.9. It just means we tried to do a channel registration before the url config could be fetched. The SDK will now wait to attempt channel creation until we have a URL.
❗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?
Airship 16.8.0 com.urbanairship.android:urbanairship-fcm com.urbanairship.android:urbanairship-automation com.urbanairship.android:urbanairship-message-center
What are the versions of any relevant development tools you are using?
Android Studio Electric Eel | 2022.1.1
Report
What unexpected behavior are you seeing?
When running UI Tests the logs are full of errors from the airship work manager. This is because we are using Hilt and workmanager ourselves and have to use an EntryPoint in our BaseApplication rather than directly injecting the HiltWorkerFactory. My own jobs (which subclass CoroutineWorker) do not error.
What is the expected behavior?
I don't see any job schedule failures in the logs.
What are the steps to reproduce the unexpected behavior?
Add Hilt and Airship to a project with work manager. The Manifest configuration should look like this:
You should have a test application like this:
And BaseApplication should look something like this:
You need a UI Test that includes the Android test rule
I don't particularly want to use Airship in my tests but despite having logic like this I still see the error
Do you have logging for the issue?
2023-02-07 11:50:37.575 29295-29295 UALib com.gocitypass.debug E The airship config options is missing URL allow list rules for SCOPE_OPEN. By default only Airship, YouTube, mailto, sms, and tel URLs will be allowed.To suppress this error, specify allow list rules by providing rules for urlAllowListScopeOpenUrl or urlAllowList. Alternatively you can suppress this error and keep the default rules by using the flag suppressAllowListError. For more information, see https://docs.airship.com/platform/android/getting-started/#url-allow-list. 2023-02-07 11:50:37.580 29295-29397 Go City - UALib com.gocitypass.debug I Airship taking off! 2023-02-07 11:50:37.580 29295-29397 Go City - UALib com.gocitypass.debug I Airship log level: 3 2023-02-07 11:50:38.010 29295-29397 Go City - UALib com.gocitypass.debug E Scheduler failed to schedule jobInfo com.urbanairship.job.SchedulerException: Failed to schedule job at com.urbanairship.job.WorkManagerScheduler.schedule(WorkManagerScheduler.java:31) at com.urbanairship.job.JobDispatcher.dispatch(JobDispatcher.java:122) at com.urbanairship.job.JobDispatcher.dispatch(JobDispatcher.java:116) at com.urbanairship.push.PushManager.dispatchUpdateJob(PushManager.java:413) at com.urbanairship.push.PushManager.updateManagerEnablement(PushManager.java:390) at com.urbanairship.push.PushManager.init(PushManager.java:346) at com.urbanairship.UAirship.init(UAirship.java:800) at com.urbanairship.UAirship.executeTakeOff(UAirship.java:422) at com.urbanairship.UAirship.access$000(UAirship.java:67) at com.urbanairship.UAirship$2.run(UAirship.java:381) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at com.urbanairship.util.AirshipThreadFactory$1.run(AirshipThreadFactory.java:50) at java.lang.Thread.run(Thread.java:764) Caused by: java.lang.IllegalStateException: The component was not created. Check that you have added the HiltAndroidRule. at dagger.hilt.internal.Preconditions.checkState(Preconditions.java:83) at dagger.hilt.android.internal.testing.TestApplicationComponentManager.generatedComponent(TestApplicationComponentManager.java:96) at com.gocitypass.HiltTestApplication_Application.generatedComponent(HiltTestApplication_Application.java:28) at dagger.hilt.EntryPoints.get(EntryPoints.java:59) at com.gocitypass.BaseApplication.getWorkManagerConfiguration(BaseApplication.kt:19) at androidx.work.impl.WorkManagerImpl.getInstance(WorkManagerImpl.java:155) at androidx.work.WorkManager.getInstance(WorkManager.java:184) at com.urbanairship.job.WorkManagerScheduler.schedule(WorkManagerScheduler.java:28) at com.urbanairship.job.JobDispatcher.dispatch(JobDispatcher.java:122) at com.urbanairship.job.JobDispatcher.dispatch(JobDispatcher.java:116) at com.urbanairship.push.PushManager.dispatchUpdateJob(PushManager.java:413) at com.urbanairship.push.PushManager.updateManagerEnablement(PushManager.java:390) at com.urbanairship.push.PushManager.init(PushManager.java:346) at com.urbanairship.UAirship.init(UAirship.java:800) at com.urbanairship.UAirship.executeTakeOff(UAirship.java:422) at com.urbanairship.UAirship.access$000(UAirship.java:67) at com.urbanairship.UAirship$2.run(UAirship.java:381) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at com.urbanairship.util.AirshipThreadFactory$1.run(AirshipThreadFactory.java:50) at java.lang.Thread.run(Thread.java:764)