作者: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. hadoop2.2编程:用ruby跑hadoop的完整实例

    Becareful!  All nodes include  need to install ruby! #!/usr/bin/ruby # Ruby code for map.rb ARGF.eac ...

  2. Xcode6新建的工程没有Frameworks文件夹了?!原来是这样

    http://stackoverflow.com/questions/24181062/default-frameworks-missing-in-xcode-6-beta They are impo ...

  3. [039] 微信公众帐号开发教程第15篇-自定义菜单的view类型(访问网页)

    引言及内容概要 距离写上一篇文章<自定义菜单的创建及菜单事件响应>整整过了两个月的时间,那时公众平台还没有开放view类型的菜单.在不久前,微信公众平台悄悄开放了view类型的菜单,却没有 ...

  4. WinForm打印之页边距

    1.启用页边距: 默认情况下PrintDocument是不理会页边距的(MS再次让人无语...),这也是为什么有人说明明设了页边距在打印预览里却没有效果的原因. 解决办法是设置PrintDocumen ...

  5. codeforces 652E Pursuit For Artifacts 边双连通分量

    题意:n个点,m条边的无向图,有的边上有标记,每条边只能走一次 给你一个起点,一个终点,询问是否能找到从起点到终点的路径,这条路径至少包含一条含有标记的边 分析:然后边双缩点 下面介绍一下边双的性质 ...

  6. lightoj 1013

    思路:动态规划.设dp[i][j][k]表示用第一个串的前i隔字符和第二个串的前k隔字符组成长度为i的串的个数,那么:若s1[j+1] == s2[k+1] dp[i+1][j+1][k+1] += ...

  7. andriod and linux kernel启动流程

    虽然这里的Arm Linux kernel前面加上了Android,但实际上还是和普遍Arm linux kernel启动的过程一样的,这里只是结合一下Android的Makefile,讲一下boot ...

  8. vijosP1049 送给圣诞夜的礼品

    vijosP1049 送给圣诞夜的礼品 链接:https://vijos.org/p/1049 [思路] 快速幂+矩阵转换. 将m次矩阵的转换看作是一次快速幂中的乘法操作,这样可以用O(log(k/m ...

  9. iOS开发——View的autoresizingMask属性

    View的自适应属性autoresizingMask属性 每一个UIView都有一个autoresizingMask属性,这个属性是用于适应父视图的大小与子视图适应的,源码如下 enum { UIVi ...

  10. HDU 1907

    博弈入门题吧. 把尼姆博弈推广到n堆,都是用异或运算.还有个总结的地方是,只要先手面对的是奇异局势,则胜负都掌握在后手.本题,题目要求是最后拿完的输,尼姆博弈是最后拿完的赢.但实际上优先权都掌握在后手 ...