Android8.0需要显示发送广播
[TOC]
概述
项目中遇到下面这样一个问题:
在Android8.0(target?=26)上面,App发送的隐式广播无法被接收到。
1 | 08-23 21:45:38.271 1207 1225 W BroadcastQueue: Background execution not allowed: receiving Intent { act=com.xxx.xxx flg=0x10 (has extras) } to com.xx.xx/com.xx.xx.receiver.XxReceiver |
原因分析:
基于以上种种原因,从Android O开始,Google做了一系列规避措施,最直接的体现在两个方面:
取消静态广播的支持。
以前很好用的静态广播消息将接收不到,比如开机广播:“android.intent.action.BOOT_COMPLETED”,
网络状态发生改变广播:“android.net.conn.CONNECTIVITY_CHANGE”。
必须以动态的方式才能接收到,这就保证了”只有用户将你的应用置为前台应用,也就是用户正在使用你的应用的时候,该应用才有可能收到广播“。这一举措旨在解决应用开机自启动泛滥的问题。
更改Service的启动方式。
如果一个应用在后台去startService(比如在broadcast中),企图在后台悄悄的运行跑流量,这将直接抛出异常。和广播类似,要启动一个服务,必须是”用户正在使用你的应用期间“才可行,或者你的服务是一个前台服务。这一举措旨在解决”应用后台自启动,成为不死应用,占用大量资源“的问题。
开机广播
对于android.intent.action.BOOT_COMPLETED 这个广播,虽然被禁用了,但是在实际的开发中还是很有必要的存在,很多操作还是需要该广播的支持。所以Google也没有把这个广播完全封死,如果应用的android:sharedUserId=“android.uid.system”,那么该应用还是可以以静态广播的方式注册和监听到它。而对于第三方应用,显然已经无法再收到这条广播了。
网络状态改变广播
对于android.net.conn.CONNECTIVITY_CHANGE,显然就没这么友好了,即使是android:sharedUserId=“android.uid.system”的应用,也将收不到静态注册的广播消息。如要接收该消息,只能是两种方式:
以动态注册广播形式注册
以静态注册广播形式注册,在AndroidManifest.xml中指明该应用的SDK为低于26,比如 < uses-sdk android:minSdkVersion=“23” android:targetSdkVersion=“23” />
影响
首先要了解一个概念。官方文档里提到implicit broadcast,可译为隐式广播,指那些没有指定接收App(即包名)的广播。
系统发送的广播毫无疑问都是隐式广播,因此基本上都会受到影响,除了部分受豁免广播之外
App发送的自定义隐式广播,都会受到影响。
如何应对这一限制
分析了受限制的原因之后,就知道该如何应对这一影响了。
- 优先使用动态注册Receiver的方式,能动态注册绝不使用Manifest注册
1 | IntentFilter intentFilter = new IntentFilter(); |
如果一定要Manifest注册,那么当发送广播的时候,指定广播接收者的包名,即发送显式广播
1 | Intent intent = new Intent("com.frewen.android.demo.action"); |
如果要接收系统广播,而对应的广播在Android8.0中无法被接收,那么只能暂时把App的targetSdkVersion改为25或以下。