本文首发微信公众号:菜天Android

忙啊~最近好忙呀。

这篇文章偷个闲,记录下 Android8.0 上的新增的广播限制。

零、前言

最近在基于 Android 8.1 的系统项目中有用到静态注册广播去监听广播。可是不论我是普通的将Apk install进去抑或是高贵的push到对应的system/priv-app/目录下,都收不到这个广播。心态,DUANG,炸了。

后来灵光一闪,扒出记忆角落的Android7.0的广播限制,赶紧Google一下。原来如此,恍然大悟:Android8.0后,当App targetSDK >= 26,几乎禁止了所有的隐式广播的静态注册监听。 特在此记录,防止我以后又提莫的忘记了。

本篇文章主要讲述以下内容,还请拿起小板凳,带好零食,前来观赏:

  • Android广播科普
  • Android8.0的后台限制
  • 具体广播限制和对应赦免清单
  • 适配/解决方法

一、科普科普广播知识

来来来,先科普下,广播两种监听/接收注册方式和两种类型,拿小本本记下来,记住了!

注册方式

  • 静态注册:也称为清单注册,就是在AndroidManifest.xml中注册的广播。此类广播接收器在 应用尚未启动 的时候就可以接收到相应广播。
  • 动态注册:也称为运行时注册,也就是在Service或者Activity组件中,通过Context.registerReceiver()注册广播接收器。此类广播接收器是在应用已启动后,通过代码进行注册。

两种类型

  • 显式广播(Explicit Broadcast):发送的Intent是显示Intent的广播。通过指定Intent组件名称来实现的,它一般用在知道目标组件名称的前提下,去调用以下方法。意图明确,指定了要激活的组件是哪个组件,一般是在相同的应用程序内部实现的。

Intent.setComponent()
Intent.setClassName()
Intent.setClass()
new Intent(A.this,B.class)

  • 隐式广播(Implicit Broadcast):通过Intent Filter来实现的,它一般用在没有明确指出目标组件名称的前提下。Android系统会根据隐式意图中设置的动作(action)、类别(category)、数据(URI和数据类型)找到最合适的组件来处理这个意图。一般是用于在不同应用程序之间。

二、Android8.0的后台执行限制

注意是针对targetSDK >= 26的应用,也就是说,targetSDK小于26的话,暂不受影响

在Oreo中,为了进一步提升用户体验,进一步节省功耗,对应用在后台运行时可以执行的操作又进一步施加了限制。

  • 后台服务限制:处于空闲状态时,限制应用的后台服务。例如:通过静态注册接收开机广播(假设你的设备没做定制,能收到~),并在onReceive方法中启动一个Service,在API 26上,是不允许且会报错的。当然,对于前台服务,这种限制是不存在的。官方说法是:前台服务更容易引起用户注意。

  • 广播限制:除了有限的例外之外,应用无法使用清单注册(静态注册)的方式来接收隐式广播

    • 但对于这些隐式广播,可以通过运行时注册(动态注册)的方式注册。
    • 对于显式广播,则依然可以通过清单注册(静态注册)的方式监听

这里多说一句,Android手机的卡顿,很大程度是由于应用滥用且自私的使用各种手段(权限滥用,广播注册,后台服务常驻等)保活或做一些PY事情。Google显然很早就意识到这一点,并从Android 6.0 开始就逐步引入各种限制,比如运行时权限和Doze。

三、具体广播限制和对应赦免清单

如果应用注册了广播接收器,那么每次发送广播后,应用的广播接收器就会消耗资源,如RAM,CPU等。如果有很多应用对系统事件广播注册广播接收器,这…,就会很卡的嘛!

所以从Android 7.0 (API 级别 24)开始,就对广播做了一些限制:

  • API24及以上应用,静态注册的广播接收器无法监听网络变化:android.net.conn.CONNECTIVITY_CHANGE
  • 在Android7.0设备上,App无法发送或者接收ACTION_NEW_PICTURE和ACTION_NEW_VIDEO广播。

只不过,在Android8.0上,又进一步的增强了限制,除了以下隐式广播外,其他所有隐式广播均无法通过在AndroidManifest.xml中注册监听。参考官网。

// Android 8.0 上不限制的隐式广播
/**
开机广播Intent.ACTION_LOCKED_BOOT_COMPLETEDIntent.ACTION_BOOT_COMPLETED
*/
"保留原因:这些广播只在首次启动时发送一次,并且许多应用都需要接收此广播以便进行作业、闹铃等事项的安排。"/**
增删用户
Intent.ACTION_USER_INITIALIZE
"android.intent.action.USER_ADDED"
"android.intent.action.USER_REMOVED"
*/
"保留原因:这些广播只有拥有特定系统权限的app才能监听,因此大多数正常应用都无法接收它们。"/**
时区、ALARM变化
"android.intent.action.TIME_SET"
Intent.ACTION_TIMEZONE_CHANGED
AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED
*/
"保留原因:时钟应用可能需要接收这些广播,以便在时间或时区变化时更新闹铃"/**
语言区域变化
Intent.ACTION_LOCALE_CHANGED
*/
"保留原因:只在语言区域发生变化时发送,并不频繁。 应用可能需要在语言区域发生变化时更新其数据。"/**
Usb相关
UsbManager.ACTION_USB_ACCESSORY_ATTACHED
UsbManager.ACTION_USB_ACCESSORY_DETACHED
UsbManager.ACTION_USB_DEVICE_ATTACHED
UsbManager.ACTION_USB_DEVICE_DETACHED
*/
"保留原因:如果应用需要了解这些 USB 相关事件的信息,目前尚未找到能够替代注册广播的可行方案"/**
蓝牙状态相关
BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED
BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED
BluetoothDevice.ACTION_ACL_CONNECTED
BluetoothDevice.ACTION_ACL_DISCONNECTED
*/
"保留原因:应用接收这些蓝牙事件的广播时不太可能会影响用户体验"/**
Telephony相关
CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED
TelephonyIntents.ACTION_*_SUBSCRIPTION_CHANGED
TelephonyIntents.SECRET_CODE_ACTION
TelephonyManager.ACTION_PHONE_STATE_CHANGED
TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED
TelecomManager.ACTION_PHONE_ACCOUNT_UNREGISTERED
*/
"保留原因:设备制造商 (OEM) 电话应用可能需要接收这些广播"/**
账号相关
AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION
*/
"保留原因:一些应用需要了解登录帐号的变化,以便为新帐号和变化的帐号设置计划操作"/**
应用数据清除
Intent.ACTION_PACKAGE_DATA_CLEARED
*/
"保留原因:只在用户显式地从 Settings 清除其数据时发送,因此广播接收器不太可能严重影响用户体验"/**
软件包被移除
Intent.ACTION_PACKAGE_FULLY_REMOVED
*/
"保留原因:一些应用可能需要在另一软件包被移除时更新其存储的数据;对于这些应用,尚未找到能够替代注册此广播的可行方案"/**
外拨电话
Intent.ACTION_NEW_OUTGOING_CALL
*/
"保留原因:执行操作来响应用户打电话行为的应用需要接收此广播"/**
当设备所有者被设置、改变或清除时发出
DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED
*/
"保留原因:此广播发送得不是很频繁;一些应用需要接收它,以便知晓设备的安全状态发生了变化"/**
日历相关
CalendarContract.ACTION_EVENT_REMINDER
*/
"保留原因:由日历provider发送,用于向日历应用发布事件提醒。因为日历provider不清楚日历应用是什么,所以此广播必须是隐式广播。"/**
安装或移除存储相关广播
Intent.ACTION_MEDIA_MOUNTED
Intent.ACTION_MEDIA_CHECKING
Intent.ACTION_MEDIA_EJECT
Intent.ACTION_MEDIA_UNMOUNTED
Intent.ACTION_MEDIA_UNMOUNTABLE
Intent.ACTION_MEDIA_REMOVED
Intent.ACTION_MEDIA_BAD_REMOVAL
*/
"保留原因:这些广播是作为用户与设备进行物理交互的结果:安装或移除存储卷或当启动初始化时(当可用卷被装载)的一部分发送的,因此它们不是很常见,并且通常是在用户的掌控下"/**
短信、WAP PUSH相关
Telephony.Sms.Intents.SMS_RECEIVED_ACTION
Telephony.Sms.Intents.WAP_PUSH_RECEIVED_ACTION注意:需要申请以下权限才可以接收
"android.permission.RECEIVE_SMS"
"android.permission.RECEIVE_WAP_PUSH"
*/
"保留原因:SMS短信应用需要接收这些广播"

呼,终于列完了,以上。可以说写的比官网还全~

建议收藏一波防止以后用的到哈。

四、解决方法

按照官方推荐,对于隐式广播,通过以下方法进行替换。

  • 动态通过调用 Context.registerReceiver()注册广播接收器而不是在清单中声明接收器。
  • 使用JobScheduler。

我选择动态注册的方式来处理这个问题。

好了,关于Oreo的广播限制的唠嗑就先唠到这里。

最近受到一位小伙伴的启发,得到一句话:努力的人,运气和机遇往往都不会差!

共勉!

五、参考链接

[1] Android Oreo 后台执行限制 https://developer.android.com/about/versions/oreo/background#broadcasts
[2] Android Oreo Implicit Broadcast Exceptions https://developer.android.com/guide/components/broadcast-exceptions
[3] Android中显式和隐式intent的特点和区别 https://blog.csdn.net/u014177843/article/details/50596863
[4] Android O行为变更–隐式广播限制 https://blog.csdn.net/hqocshheqing/article/details/76850164

欢迎关注微信公众号
菜天Android
主推 Android 干货文章
关注得 Android 详细知识图谱

为什么 Android 8.0 注册的广播接收不到了?相关推荐

  1. android5.0 广播失效,解决Android 8.0及以上系统接收不到广播的问题

    最近把自己的手机系统升级到了android 8.0,然后以前能正常运行的项目,莫名其妙的出了问题,有个地方广播接收不到了,然后分别在6.0和7.0的设备上运行了项目,发现一切正常,擦,估计是高版本系统 ...

  2. Android 7.0 隐式广播-监听网络变化

    Android7.0前,Android系统前网络切换时,会发广播,业务只要监听广播即可. public class NetChangeReceiver extends BroadcastReceive ...

  3. Android 7.0 ActivityManagerService(5) 广播(Broadcast)相关流程分析

    本篇博客旨在分析Android中广播相关的源码流程. 一.基础知识 广播(Broadcast)是一种Android组件间的通信方式. 从本质上来看,广播信息的载体是intent.在这种通信机制下,发送 ...

  4. android 静态广播无效,Android8.0静态广播接收静态注册无效,并实现全局网络监听...

    解决方案: 在APP的Activity中对广播接收进行动态注册即可完成. public class NetWorkStateReceiver extends BroadcastReceiver { @ ...

  5. Android 9.0系统源码_广播(一)广播的注册

    前言 广播作为四大组件之一,使用频率远没有Activity高,但是广播的工作过程还是十分有必要了解的.本系列文章将会逐步讲述广播的注册.发送和接受:而本篇我们要讲的就是广播的注册. 广播的注册分为两种 ...

  6. Android AOSP 6.0.1 registerReceiver广播注册流程分析

    广播作为 Android 开发的四大组间之一,当我们发送广播以后,发生了什么?广播接收者最终如何收到了广播. 一.复盘广播的使用 在 Android 开发中使用广播分为三个步骤: 1.新建广播接收者 ...

  7. 【Android 电量优化】电量优化 ( 充电状态获取 | 主动获取充电状态 | 广播接受者监听充电状态 | 被动获取充电状态 | 注册空广播接受者获取历史广播 )

    文章目录 一.获取充电状态 二.被动获取充电状态 三.主动获取充电状态 参考 Google 官方文档 : 优化电池续航时间 一.获取充电状态 在应用中执行某些操作 , 如软件云端备份 , 从服务器端获 ...

  8. 前台如何正确接收流信息_如何绕过 Android 8.0 startService 限制?

    ❝ 应用在后台运行时,会消耗一部分有限的设备资源,例如 RAM.这可能会影响用户体验,如果用户正在使用占用大量资源的应用(例如玩游戏或观看视频),影响会尤为明显.为了提升用户体验,Android 8. ...

  9. Android 广播接收不到短信问题,Android中短信的广播接收问题

    首先,接收短信的机制是接收广播,由系统发出短信到来的广播,我们对短信广播进行注册,从而接收. import java.util.Date; import android.content.Broadca ...

最新文章

  1. 使用VMwork Station Pro 14 安装CentOS7.6详细教程
  2. Visual Studio 2013或2015工程属性中包含目录和库目录的添加方法,附加依赖项,相对路径
  3. Ⅵ:zookeeper的Watcher事件监听机制
  4. 采用组策略Loopback功能限制文件夹重定向路径
  5. asp.net mvc4使用DropDownList
  6. 编译redis-5.0.9报错zmalloc.h:50:31: 致命错误:jemalloc/jemalloc.h:没有那个文件或目录问题解决
  7. VisualTreeHelper不仅仅只是用来查看可视化树结构的
  8. CATIA转的STP打开什么都没有_ProE打开Creo7.0模型文件的方法视频教程
  9. 分享一个奇葩SM2258XT板子(100-H00112581-590)没有CE跳线,只有CE飞线,顺便量产开卡
  10. springboot呼伦贝尔旅游网站的设计与实现毕业设计源码091833
  11. linux 统一设备模型 pci,【原创】Linux PCI驱动框架分析(二)
  12. keil中出现警告:last line of file ends without a newline解决方法
  13. 神雕侠侣手游服务器维护,《神雕侠侣》3月30日更新维护新服开启公告
  14. Udesk即时通讯网页插件发送咨询对象(一、使用内嵌代码)
  15. java打雪仗,linux jdk安装--转载
  16. OSChina 周五乱弹 ——一句话总结程序员的2017
  17. 步进电机基础(2.6)-直线步进电机
  18. Word如何对齐冒号,想把几行的冒号对齐该怎么设置?
  19. 西北农林科技大学考研计算机大纲,2021年西北农林科技大学考研真题大纲参考书目...
  20. 工业生产中的“主动刹车”,是怎么实现的?

热门文章

  1. wxParse多数据循环使用方法
  2. SerializationException: Could not read JSON: Unrecognized token “xxx“
  3. 公司组网网络解决方案和企业常用的组网技术有哪些?
  4. DELLEMC R7 RAID5的配置和u盘安装操作系统+ip地址的配置+修改成eth0 最全!!!
  5. 商务人士邮箱推荐?高大上邮箱来了!
  6. C/C++编程学习 - 第4周 ② 甲流疫情死亡率
  7. 申宝股票-热点板块退潮
  8. 问答|多重曝光相关论文有哪些?
  9. QT socket网络编程
  10. PHP 网络游戏防沉迷接口 代码与坑