NotificationListenerService不能监听到通知,研究了一天不知道是什么原因?

关注者
36
被浏览
55,034

6 个回答

更新解决方案:

gist.github.com/xinghui

-------------------------

背景知识:

所属: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


蓝色:已授权的通知监听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));

这个问题我最近也在跟踪,NLS时而能工作(尤其是重启手机后),时而不能工作(并不同于网上很多人提到问题出现后只能重启手机,我这里似乎故障后不知道触发什么条件NLS又起作用了)

NLS 出现问题后去getRunningServices枚举系统中运行的服务,可以看到是服务进程已经消失了!

现在每天大概花1-2个小时找相关资料,这么干了有4天了,找到的有价值的信息包括:

Android 4.4 KitKat NotificationManagerService使用详解与原理分析(二)__原理分析

android - NotificationListenerService stopping and can't be restarted without a reboot

android - NotificationListenerService gets killed but never restarted

code.google.com/p/andro

从 SDK 源代码里可以看到(5.x 之后的源代码在 com/android/server/notification/ManagedServices.java),系统应该对服务进程退出做了处理...目前还在研究中


====2016.01.22 更新

现在基本可以确认,是因为服务进程被主机杀掉了

中国的手机ROM现在都会自动杀不活跃的进程,也能设置保护。我把开发的服务设置为保护后就不再有问题,一直稳定运行

研究了很长时间,包括去Patch framework框架里的services.jar,最后居然是这样的一个结果...