The issue is described on Stackoverflow
https://stackoverflow.com/questions/62335727/hilt-injection-not-working-with-broadcastreceiver
I am not the poster, but I did encounter the same issue.
This workaround prevented the crash:
override fun onReceive(context: Context, intent: Intent?) {
val injector = BroadcastReceiverComponentManager.generatedComponent(context) as AppBroadcastReceiver_GeneratedInjector
injector.injectAppBroadcastReceiver(UnsafeCasts.unsafeCast(this))
Another workaround is to use a class like this:
abstract class DaggerBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {}
}
Now extend this class instead of BroadcastReceiver and you can call super.onReceive().
Injection happens in the super method. Just to check, are you calling super.onReceive?
For example:
@AndroidEntryPoint
class MyBroadcastReceiver : BroadcastReceiver() {
@Inject lateinit var foo: Foo
override fun onReceive(context: Context?, intent: Intent?) {
super.onReceive(context, intent) // injection happens here
//... Do something with foo
}
}
@bcorso It is not possible to call super.onReceive because onReceive is an abstract method.
https://developer.android.com/reference/android/content/BroadcastReceiver#onReceive(android.content.Context,%20android.content.Intent)
public abstract void onReceive(Context context, Intent intent)
Ah, thanks! In that case, another workaround is to use the long-form of @AndroidEntryPoint. With the long-form notation you extend the generated class directly so the super.onReceive exists:
@AndroidEntryPoint(BroadcastReceiver::class)
class MyBroadcastReceiver : Hilt_MyBroadcastReceiver() {
@Inject lateinit var foo: Foo
override fun onReceive(context: Context?, intent: Intent?) {
super.onReceive(context, intent) // injection happens here
//... Do something with foo
}
}
We'll have to think about if there's a way we can support this better with the short-form of the annotation.
I do like @Thomas-Vos's suggestion, https://github.com/google/dagger/issues/1918#issuecomment-644057247, because it avoids referencing the generated Hilt_ class. It might make sense to define the class within Hilt for this use case.
@sunilson The AppWidgetProvider class already overrides the onReceive function. That means you can just add @AndroidEntryPoint to your widget class that extends AppWidgetProvider and it should work fine.
I realized a few minutes after I posted this (don't know why it didn't work from the start) and removed my comment, but your answer was too fast 馃槄 Thanks anyway for your response!
We're still seeing this issue on 2.29.1. The changelog says this fix made it in - is that true?
@danh32 Yes, this should be fixed in 2.29.1. The fix is mostly in the Hilt Gradle Plugin, can you confirm your plugin is also updated? If this is still occurring can you please share more of your BroadcastReceiver mainly the onReceive method and the class signature as in, what does it extend and if extends a class you own, is it abstract, does it implement onReceive too?
馃う You're totally right, our gradle plugin version was defined separately and was far behind. Sorry about that!
@danysantiago
I still have an issue on our CI (not happening on my PC) :
javassist.bytecode.BadBytecode: onReceive (Landroid/content/Context;Landroid/content/Intent;)V in com.myapp.geofence.GeofenceBroadcastReceiver: failed to resolve types
I'll see if I can work on a sample
EDIT: couldn't reproduces it as I try on my computer... Do you have any insight on why it would build on a machine and not the other? Could it be the java runtime/jdk version? (as the CI does not use Android Studio to build, only gradle, but in the same time I tried to use gradle on my pc and it still works).
After using --stacktrace, here's the missing type:
Caused by: javassist.NotFoundException: kotlinx.coroutines.Job
Fix :
So basically, I had
override fun onReceive(context: Context, intent: Intent) {
GlobalScope.launch {
//Doing stuff
}
}
I moved the code in another method
override fun onReceive(context: Context, intent: Intent) {
myMethod()
}
fun myMethod() {
GlobalScope.launch {
//Doing stuff
}
}
and voil脿!
Are there any known issues with testing a BroadcastReceiver that needs Hilt injection?
Hilt seems to be injecting into my BroadcastReceiver when run from the context of an app, but doesn't seem to do any inject when run from the context of a test class annotated with HiltAndroidTest.
UPDATE: It would seem that I am just running into this known issue https://dagger.dev/hilt/robolectric-testing.html
After using the 2.29.1-alpha I have this build error message
Execution failed for task ':common:core-legacy:transformClassesWithAndroidEntryPointTransformForDebug'.
javassist.bytecode.BadBytecode: onReceive (Landroid/content/Context;Landroid/content/Intent;)V in foo.bar.login.service.ConfirmSmsReceiver: failed to resolve types
stacktrace:
* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':common:core-legacy:transformClassesWithAndroidEntryPointTransformForDebug'.
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.java:205)
at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:263)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:203)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:184)
at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:114)
at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:62)
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:416)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:406)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:102)
at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36)
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:41)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:372)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:359)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:352)
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:338)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:127)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:191)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:182)
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:124)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
Caused by: java.lang.RuntimeException: javassist.bytecode.BadBytecode: onReceive (Landroid/content/Context;Landroid/content/Intent;)V in foo.bar.login.service.ConfirmSmsReceiver: failed to resolve types
at com.android.builder.profile.Recorder$Block.handleException(Recorder.java:55)
at com.android.builder.profile.ThreadRecorder.record(ThreadRecorder.java:108)
at com.android.build.gradle.internal.pipeline.TransformTask.transform(TransformTask.java:242)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:104)
at org.gradle.api.internal.project.taskfactory.IncrementalTaskInputsTaskAction.doExecute(IncrementalTaskInputsTaskAction.java:47)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:42)
at org.gradle.api.internal.project.taskfactory.AbstractIncrementalTaskAction.execute(AbstractIncrementalTaskAction.java:25)
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:28)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$3.run(ExecuteActionsTaskExecuter.java:568)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:92)
at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:553)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:536)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.access$300(ExecuteActionsTaskExecuter.java:109)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.executeWithPreviousOutputFiles(ExecuteActionsTaskExecuter.java:276)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.execute(ExecuteActionsTaskExecuter.java:265)
at org.gradle.internal.execution.steps.ExecuteStep.lambda$execute$0(ExecuteStep.java:32)
at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:32)
at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:26)
at org.gradle.internal.execution.steps.CleanupOutputsStep.execute(CleanupOutputsStep.java:67)
at org.gradle.internal.execution.steps.CleanupOutputsStep.execute(CleanupOutputsStep.java:36)
at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:49)
at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:34)
at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:43)
at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:73)
at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:54)
at org.gradle.internal.execution.steps.CatchExceptionStep.execute(CatchExceptionStep.java:34)
at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:44)
at org.gradle.internal.execution.steps.SnapshotOutputsStep.execute(SnapshotOutputsStep.java:54)
at org.gradle.internal.execution.steps.SnapshotOutputsStep.execute(SnapshotOutputsStep.java:38)
at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:49)
at org.gradle.internal.execution.steps.CacheStep.executeWithoutCache(CacheStep.java:159)
at org.gradle.internal.execution.steps.CacheStep.execute(CacheStep.java:72)
at org.gradle.internal.execution.steps.CacheStep.execute(CacheStep.java:43)
at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:44)
at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:33)
at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:38)
at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:24)
at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:92)
at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$0(SkipUpToDateStep.java:85)
at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:55)
at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:39)
at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:76)
at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:37)
at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:36)
at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:26)
at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:94)
at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:49)
at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:79)
at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:53)
at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:74)
at org.gradle.internal.execution.steps.SkipEmptyWorkStep.lambda$execute$2(SkipEmptyWorkStep.java:78)
at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:78)
at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:34)
at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:39)
at org.gradle.internal.execution.steps.LoadExecutionStateStep.execute(LoadExecutionStateStep.java:40)
at org.gradle.internal.execution.steps.LoadExecutionStateStep.execute(LoadExecutionStateStep.java:28)
at org.gradle.internal.execution.impl.DefaultWorkExecutor.execute(DefaultWorkExecutor.java:33)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:192)
... 30 more
Caused by: javassist.bytecode.BadBytecode: onReceive (Landroid/content/Context;Landroid/content/Intent;)V in foo.bar.login.service.ConfirmSmsReceiver: failed to resolve types
at javassist.bytecode.stackmap.MapMaker.make(MapMaker.java:119)
at javassist.bytecode.MethodInfo.rebuildStackMap(MethodInfo.java:458)
at dagger.hilt.android.plugin.AndroidEntryPointClassTransformer.transformOnReceive(AndroidEntryPointClassTransformer.kt:237)
at dagger.hilt.android.plugin.AndroidEntryPointClassTransformer.transformClass(AndroidEntryPointClassTransformer.kt:134)
at dagger.hilt.android.plugin.AndroidEntryPointClassTransformer.transformClassToOutput(AndroidEntryPointClassTransformer.kt:106)
at dagger.hilt.android.plugin.AndroidEntryPointClassTransformer.transformFile(AndroidEntryPointClassTransformer.kt:102)
at dagger.hilt.android.plugin.AndroidEntryPointTransform.transformFile(AndroidEntryPointTransform.kt:156)
at dagger.hilt.android.plugin.AndroidEntryPointTransform.transform(AndroidEntryPointTransform.kt:124)
at com.android.build.gradle.internal.pipeline.TransformTask$2.call(TransformTask.java:284)
at com.android.build.gradle.internal.pipeline.TransformTask$2.call(TransformTask.java:247)
at com.android.builder.profile.ThreadRecorder.record(ThreadRecorder.java:106)
... 92 more
Caused by: javassist.bytecode.BadBytecode: failed to resolve types
at javassist.bytecode.stackmap.MapMaker.make(MapMaker.java:177)
at javassist.bytecode.stackmap.MapMaker.make(MapMaker.java:116)
... 102 more
Caused by: javassist.NotFoundException: kotlin.text.MatchResult
at javassist.ClassPool.get(ClassPool.java:430)
at javassist.bytecode.stackmap.TypeData$TypeVar.fixTypes2(TypeData.java:437)
at javassist.bytecode.stackmap.TypeData$TypeVar.fixTypes(TypeData.java:410)
at javassist.bytecode.stackmap.TypeData$TypeVar.dfs(TypeData.java:357)
at javassist.bytecode.stackmap.MapMaker.fixTypes(MapMaker.java:402)
at javassist.bytecode.stackmap.MapMaker.make(MapMaker.java:175)
... 103 more
Edit: @NitroG42 workaround did work, It couldn't resolve koltin.text.toRegex ext fun
Most helpful comment
Another workaround is to use a class like this:
Now extend this class instead of
BroadcastReceiverand you can callsuper.onReceive().