作者: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操作。

  1. private void toggleNotificationListenerService() {
  2. PackageManager pm = getPackageManager();
  3. pm.setComponentEnabledSetting(new ComponentName(this, com.xinghui.notificationlistenerservicedemo.NotificationListenerServiceImpl.class),
  4. PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
  5. pm.setComponentEnabledSetting(new ComponentName(this, com.xinghui.notificationlistenerservicedemo.NotificationListenerServiceImpl.class),
  6. PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
  7. }

问题解决。

补充:

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

  1. private static boolean isNotificationListenerServiceEnabled(Context context) {
  2. Set<String> packageNames = NotificationManagerCompat.getEnabledListenerPackages(context);
  3. if (packageNames.contains(context.getPackageName())) {
  4. return true;
  5. }
  6. return false;
  7. }

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

  1. 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. 解决MYSQL 8小时连接问题

    之前在使用SSH开发项目的时候遇到了一个很奇怪的问题,部署到服务器上,运行一段时间后系统就崩溃了. 出现错误:org.hibernate.exception.JDBCConnectionExcepti ...

  2. 【HDOJ】1504 Disk Tree

    文件可以重名.先按字典序将路径排序,再过滤掉公共前缀.其中的问题是'\'的ASCII比[A-Z0-9]大,将它替换为空格.否则字典序有问题. /* 1504 */ #include <iostr ...

  3. URAL1009

    链接 第一道URAL题 简单递推 #include <iostream> #include<cstdio> #include<cstring> #include&l ...

  4. 用if else 判断是不是7的倍数等

    static void Main(string[] args)        {            while (true)            {                int b; ...

  5. Xcode 升级后, 插件无法使用的问题( PluginLoading: Required plug-in compatibility UUID.... )

    find ~/Library/Application\ Support/Developer/Shared/Xcode/Plug-ins -name Info.plist -maxdepth 3 | x ...

  6. c# 无损高质量压缩图片代码

    /// <summary> /// 无损压缩图片 /// </summary> /// <param name="sFile">原图片</ ...

  7. epub格式电子书剖析之三:NCX文件构成

    ncx文件是epub电子书的又一个核心文件,用于制作电子书的目录,其文件的命名通常为toc.ncx. ncx文件是一个XML文件,该标准由DAISY Consortium发布(参见http://www ...

  8. 数学物理学报Offprints and Remuneration

  9. [Raobin] Ext.net在前端直接将对象转为json形式传入后台

    d.Render.ExtraParams.Add(Html.Y().Parameter("Json", new JavaScriptSerializer().Serialize(e ...

  10. Python能做什么

       There should be one--and preferably only one --obvious way to do it. 首先,对于小白来说,Python比较容易上手.额就是个活 ...