作者:Hugo
链接:https://www.zhihu.com/question/33540416/answer/113706620
来源:知乎
著作权归作者所有,转载请联系作者获得授权。

背景知识:

所属:android.service.notification.NotificationListenerService

作用:监听通知栏内容变化的服务

  1. extends Service,abstract class(意味着第三方可以实现去接收通知栏的通知数据)。
  2. Added in API level 18(Android 4.3)。
  3. 应用场景:智能手表(Google官方的Android Wear手机端App,通知消息同步到手表。如下图)、红包助手(监听通知栏的微信红包消息)等。
  4. Service bind时机:在系统的设置通知授权中勾选并授权时。
  5. 回调时机:有新通知或通知被移除或通知排序变化时系统回调。

----坑------

应用进程被杀后再次启动时,服务不生效(没有bindService)(在下图所示的蓝色列表名单中,不在红色的存活名单中)。

影响:通知栏有内容变更,服务无法感知。

还原方法:重启手机

必现手机(方便调试):小米Note Pro,清除后台应用后。

我们要做的:让服务重生。

调试手段:查看存活的通知监听服务。

方法:adb shell dumpsys notification

<img src="https://pic4.zhimg.com/fad5065af404878506a7ed548f5854d7_b.jpg" data-rawwidth="964" data-rawheight="278" class="origin_image zh-lightbox-thumb" width="964" data-original="https://pic4.zhimg.com/fad5065af404878506a7ed548f5854d7_r.jpg">

蓝色:已授权的通知监听Service列表。

红色:当前存活的的通知监听Service列表。

调查思路:
一、第三方应用主动注册
二、触发系统重新bind

思路一:第三方应用主动注册

关键代码路径:

  • android.service.notification.NotificationListenerService#registerAsSystemService
  • android.app.INotificationManager.Stub#enforceSystemOrSystemUI

条件:

  • 系统的uid或有android.permission.STATUS_BAR_SERVICE权限。

∴ 路不通。

思路二:触发系统重新bind

关键代码路径:

  • com.android.server.notification.ManagedServices#rebindServices

三种方式触发:

  1. A && B(A:应用安装卸载或更新等的广播;B:上图蓝色列表中的服务有变化)。
  2. 系统的登录用户切换 。[pass]
  3. Settings.Secure.ENABLED_NOTIFICATION_LISTENERS的Settings值有变更。

第三方有权利触发的方式(源码分析得知 1B= 3):

  • Service的disable,会有Intent.ACTION_PACKAGE_CHANGED广播,并且从上图蓝色列表中移除。

利用这一特性,把应用的NotificationListenerService实现类disable再enable,即可触发系统rebind操作。

private void toggleNotificationListenerService() {
PackageManager pm = getPackageManager();
pm.setComponentEnabledSetting(new ComponentName(this, com.xinghui.notificationlistenerservicedemo.NotificationListenerServiceImpl.class),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); pm.setComponentEnabledSetting(new ComponentName(this, com.xinghui.notificationlistenerservicedemo.NotificationListenerServiceImpl.class),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); }

问题解决。

补充:

1、怎样在代码中判断自己的服务是否在上图蓝色列表(通知已授权)中?

private static boolean isNotificationListenerServiceEnabled(Context context) {
Set<String> packageNames = NotificationManagerCompat.getEnabledListenerPackages(context);
if (packageNames.contains(context.getPackageName())) {
return true;
}
return false;
}

2、怎样发起通知授权流程。

startActivity(new Intent(NotificationConstants.ACTION_NOTIFICATION_LISTENER_SETTINGS));

NotificationListenerService不能监听到通知的更多相关文章

  1. oninput事件(解决onkeyup无法监听到复制黏贴)

    change事件需要两个条件触发: a)当前对象属性改变,并且是由键盘或鼠标事件激发的(脚本触发无效) b)当前对象失去焦点(onblur)  keypress  能监听键盘事件,但鼠标复制黏贴操作就 ...

  2. vue计算属性无法监听到数组内部变化

    计算属性可以帮助我们简化代码,做到实时更新,不用再自己添加function去修改data. 首先看一下计算属性的基本写法(摘自官网) var vm = new Vue({ el: '#demo', d ...

  3. cordova-plugin-file-transfer 监听到下载成功,找不到文件 - 简书

    原文:cordova-plugin-file-transfer 监听到下载成功,找不到文件 - 简书 下载成功后找不到下载文件 function download(fileEntry, uri) { ...

  4. laravel中observe不能监听到updated事件原因

    //这种方式不行Student::where('id', $request->student_id)->update($student); $findStudent = Student:: ...

  5. UNLISTEN - 停止监听通知信息

    SYNOPSIS UNLISTEN { name | * } DESCRIPTION 描述 UNLISTEN 用于删除一个现有的已注册的 NOTIFY 事件. UNLISTEN 取消当前 Postgr ...

  6. vue中watch和computed为什么能监听到数据的改变以及不同之处

    先来个流程图,水平有限,凑活看吧-_-|| 首先在创建一个Vue应用时: var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } ...

  7. Zookeeper 对节点的 watch监听通知是永久的吗?为什么 不是永久的?

    不是.官方声明:一个 Watch 事件是一个一次性的触发器,当被设置了 Watch 的数据发生了改变的时候,则服务器将这个改变发送给设置了 Watch 的客户端, 以便通知它们. 为什么不是永久的,举 ...

  8. Oracle LISTENER 主机名修改为IP地址后LISTENER无法监听到实例 oracle监听错误与hosts文件配置

    为什么listener.ora文件里面HOST后面到底应该输入IP地址还是主机名.我的经验告诉我,这边最好使用主机名.很多的时候,一个机器绑定的不只一个IP地址,如HOST后面是IP地址,那么ORAC ...

  9. mui.fire 目标页无法监听到 触发事件

    //获得详情页面 if(!detailPage){ detailPage = plus.webview.getWebviewById('detail.html'); } //触发详情页面的newsId ...

随机推荐

  1. str.match(regex)与regex.exec(str)对比解析,从此不再晕

    match属于字符串的方法,exec属于正则表达式的方法.其中regex是否有g标志的区别经常搞不清,所以测试记录下. 1.str.match(regex) regex中无g标志 返回一个数组,arr ...

  2. 【HDOJ】1502 Regular Words

    大数+DP,感觉这个DP有点儿抽象,而且这个是大数,wa了很多次. #include <stdio.h> #define MAXNUM 61 #define MAXLEN 100 type ...

  3. Oracle 常用符号CHR

    select  chr(92)||chr(102) from dual; \f select  chr(92)||chr(110) from dual; \n select  chr(92)||chr ...

  4. Emeditor所有快捷键操作

    新建文本    Ctrl+N         创建一个新的文本文件. 打开         Ctrl+O    打开一个已存在的文件. 保存         Ctrl+S     保存当前文件. 重新 ...

  5. 基于WebForm+EasyUI的业务管理系统形成之旅 -- 系统设置(Ⅰ)

    上篇<基于WebForm+EasyUI的业务管理系统形成之旅 -- 总体介绍>,主要介绍系统总体的界面效果和用户体验UI设计. 在MVC.MVP大行其道的今天,写WebForm该系列篇章, ...

  6. [codevs1287]矩阵乘法

    题目描述 Description 小明最近在为线性代数而头疼,线性代数确实很抽象(也很无聊),可惜他的老师正在讲这矩阵乘法这一段内容.当然,小明上课打瞌睡也没问题,但线性代数的习题可是很可怕的.小明希 ...

  7. Java笔记(二十九)……网络编程

    概述 网络模型 网络通讯的要素 ip地址:网络中设备的标识符 端口:用于标识同一台设备上不同的进程,有效端口:0~65535,其中0~1024是系统使用端口或者保留端口 TCP与UDP UDP特点: ...

  8. Linux串口调试

    shell方式 1.使用minicon -s配置串口并保存: 2.使用setserial /dev/ttyUSB0 -a等查看串口配置: 3.接收侧cat /dev/ttyUSB0等待串口输出: 4. ...

  9. json.net json转换神器

    json.nethttps://json.codeplex.com/ api documenthttp://james.newtonking.com/json/help/index.html#

  10. poj1273--Drainage Ditches(最大流Edmond-Karp算法 邻接表实现)

    最大流模板题 大部分Edmond-Karp算法代码都是邻接矩阵实现,试着改成了邻接表. #include <iostream> #include <cstdio> #inclu ...