Bootstrap

Background execution not allowed,广播无法接收原因及解决方法

    出现此报错的原因是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的方式,项目紧急可以使用,但也相当于埋下一个坑,如果后需源码发生变化,项目进行更新的话,很可能踩到这个坑上,因此使用还需谨慎。
    以上各种方法希望能帮助到各位~

;