出现此报错的原因是Android O中对隐式广播做了限制,这种限制主要是把广播用于进程间通信时,广播Receiver无法接收到广播,如果发生了此现象,可以通过shell下 logcat -s BroadcastQueue 可以看到是否报出了这样的警告。
11-01 13:58:45.617 2432 2549 W BroadcastQueue: Background execution not allowed: receiving Intent:***
应对方案
一、这里的AndroidO并不是运行的Android版本,而是在AndroidManifest文件中定义的targetSdkVersion的值,因此我们第一种方法也是最稳定的方法即把项目文件中的targetSdkVersion设置为25及以下的版本号,重新编译即可,如果用的AndroidStudio,还要修改module/build.gradle中的该项配置。
二、如果项目依赖Android O,无法修改编译版本的话,可以把静态广播修改为动态广播,因为此项限制的原因即是系统与后台应用自启之间的战争,动态广播在申请某项权限时会经过用户同意,因此是系统允许的,修改为动态广播后即可正常接收。
三、如果不是接收系统广播,只是两个应用间进行通信的话,可以在发送时为intent指定包名,这样接受者静态注册也是可以接收到广播的。
Intent mIntent = new Intent(Broadcast_Action);
mIntent.setPackage(Package_Name);
sendBroadcast(mIntent);
四、如果项目必须以一对多的方式发送广播,并且接收者无法动态注册的话,那么可以给Intent增加一个FLAG_RECEIVER_INCLUDE_BACKGROUND的Flag,不过这个标志位在源码中被hide掉了。
但我们可以直接用他的属性值,这样也是有效的。
intent.addFlags(0x01000000);
具体原因可以看下BroadcastQueue的源码:
} else if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)
|| (r.intent.getComponent() == null
&& r.intent.getPackage() == null
&& ((r.intent.getFlags()
& Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0)
&& !isSignaturePerm(r.requiredPermissions))) {
mService.addBackgroundCheckViolationLocked(r.intent.getAction(),
component.getPackageName());
Slog.w(TAG, "Background execution not allowed: receiving "
+ r.intent + " to "
+ component.flattenToShortString());
skip = true;
}
之所以打印了Background execution not allowed的log,是满足了这个if的4个条件:
1、r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0
2、r.intent.getComponent() == null
3、r.intent.getPackage() == null
4、(r.intent.getFlags() & Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0 && !isSignaturePerm(r.requiredPermissions)
首先,我们不会指定Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND,因此条件1肯定为false,而Component和Package如果没有设置的话这里条件2,3就为true了,所以关键就是看条件4是否满足了,只要在Intent中包含了FLAG_RECEIVER_INCLUDE_BACKGROUND标志位,条件4就肯定为false了,这个if的条件就不满足了,后续逻辑也就正常执行。
但是,这毕竟是谷歌hide的方式,项目紧急可以使用,但也相当于埋下一个坑,如果后需源码发生变化,项目进行更新的话,很可能踩到这个坑上,因此使用还需谨慎。
以上各种方法希望能帮助到各位~