• NotificationListenerService不能监听到通知


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


    蓝色:已授权的通知监听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));
  • 相关阅读:
    Jquery对象与DOM对象之间的转换
    关于Content-Type中application/x-www-form-urlencoded 和 multipart/form-data的区别及用法
    ${pageContext.request.contextPath} :JSP取得绝对路径方法
    servlet到底是什么?
    get和post的区别
    HTTP请求返回状态码详解
    XMLHttpRequest对象的readyState和status区别
    hdu 3594 仙人掌图
    hdu 4744 最小费用流
    hdu 4729 树链剖分
  • 原文地址:https://www.cnblogs.com/dongweiq/p/5997210.html
Copyright © 2020-2023  润新知