Android 12.0 应用中监听系统收到的通知

news2024/11/26 20:24:56

Android 12.0 通知简介icon-default.png?t=N7T8https://blog.csdn.net/Smile_729day/article/details/135502031?spm=1001.2014.3001.5502 

1. 需求

在系统内置应用中或者在第三方应用中,获取Android系统收到的通知的内容.

2. NotificationListenerService 接口

Android 系统预留了专门的API, 即 NotificationListenerService 接口,它的源码路径为:

源码路径 : /frameworks/base/core/java/android/service/notification/NotificationListenerService.java


public abstract class NotificationListenerService extends Service {

              ......

3. 实现 NotificationListenerService

NotificationListenerService 是抽象类,通过在 Service 中实现该抽象类,并实现需要的接口,代码如下:

public class MyNotificationListenerService extends NotificationListenerService {

    //当系统收到新的通知时,会触发该接口
    @Override
    public void onNotificationPosted(StatusBarNotification sbn) {
       
     addAlienNotificationInfo(sbn); //获取通知的内容
    }

    //当系统移除通知时,即在通知列表中清除通知时,或者卸载应用时,该应用包名下的通知都会被清除,也同样会会触发该接口
    @Override
    public void onNotificationRemoved(StatusBarNotification sbn) {
        super.onNotificationRemoved(sbn);
    }
}

上面两个接口,第一个是监听系统新通知,第二个是监听系统通知清除,如果看过Android Systemui 中有关通知的内容,就会发现,System UI 对通知的显示和通知的清除,同样也是继承该API.

下面,分析当系统收到新通知时,如何解析出通知里的内容.

4. 获取通知内容

   private void addAlienNotificationInfo(StatusBarNotification sbn) {

        String packageName = sbn.getPackageName();//获取发送通知的包名
        
        Notification notification = sbn.getNotification(); //获得一个Notification对象

        Bundle extras = notification.extras;

        RemoteViews contentView = notification.contentView;

        //ApplicationInfo appInfo = extras.getParcelable(NotificationCompat.EXTRA_BUILDER_APPLICATION_INFO);//如果是系统内置应用,可以获取到ApplicationInfo ,后面会有解释
        //String appName = appInfo.loadLabel(mPm).toString(); //如果是系统内置的应用,可以通过ApplicationInfo对象获取通知发送这条通知的应用名

        String category = notification.category;

        String channelId = notification.getChannelId();

        //String className = getNotificationClassName(notification);//如果是系统内置应用,可以获取到通知中设置的Intent,后面会有解释

        int color = notification.color;//通知setColor()设置的颜色

        boolean defaultVibrate = (notification.vibrate == null) ? true : false;

        String notificationVibrationString = Arrays.toString(notification.vibrate);

        int importance = notification.priority; //通知的重要性
        

        String key = sbn.getKey();//通知的Key,删除通知时,需要通过Key来确定删除哪条通知

        Icon myLargeIconToIcon = extras.getParcelable(Notification.EXTRA_LARGE_ICON);//获取通知设置的大图片,即setLargeIcon() ,
        

        int ledColor = notification.ledARGB;//通知led灯颜色

        String sound = (notification.sound != null) ? notification.sound.toString() : null;

        int progress = extras.getInt(Notification.EXTRA_PROGRESS);//当前进度值
        int progressMax = extras.getInt(Notification.EXTRA_PROGRESS_MAX);//设定的最大进度值
        boolean progressIndeterminate = extras.getBoolean(Notification.EXTRA_PROGRESS_INDETERMINATE);//是否在通知中显示进度值


        int flagsToCheck = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR;

        boolean resident = (notification.flags & flagsToCheck) != 0;//是否是常驻通知(前台&onging),类似于音乐应用,


        String smallIcon = notification.getSmallIcon().toString();//通知设置的smallIcon()

        String title = (String) extras.get(Notification.EXTRA_TITLE);//通知标题
        String subText = (String) extras.get(Notification.EXTRA_SUB_TEXT);//通知附加内容
        String text = (String) extras.get(Notification.EXTRA_TEXT);//通知内容


        boolean userRemovable = (notification.flags & Notification.FLAG_AUTO_CANCEL) != 0; //是否可移除通知,即 setAutoCancel(boolean autoCancel) 中设定的值

        long when = notification.when;//通知的时间

        String template = getNotificationTemplate(notification);//获取通知的类型,下面会详细介绍

        //BigTextStyle通知中,bigText的内容
        String bigText = (String) extras.getCharSequence(Notification.EXTRA_BIG_TEXT);    

        //BigPictureStyle通知中设置的大图片
        Bitmap picture_extraBitmap = extras.getParcelable(Notification.EXTRA_PICTURE);

        //状态栏通知列表中,折叠时是否显示图片,注意:该属性在Android12上有,Android11上没有,
        boolean mShowBigPictureWhenCollapsed = extras.getBoolean(Notification.EXTRA_SHOW_BIG_PICTURE_WHEN_COLLASED);


       //通过下面的方法也可以查看通知中的设置的全部参数
        for(String mykey : notification.extras.keySet()){
            String ex = " " + mykey +" => " + notification.extras.get(mykey)+ ";";
            Log.d(TAG,"ex="+ex);
        }
}

(1) 获取ApplicationInfo

      上面在获取通知的ApplicationInfo时,使用了 Notification.EXTRA_BUILDER_APPLICATION_INFO,该值不对系统外开放,如下源码所示:

源码路径:/frameworks/base/core/java/android/app/Notification.java
 
/**
     * @hide
     */
    public static final String EXTRA_BUILDER_APPLICATION_INFO = "android.appInfo";

(2) getNotificationClassName(notification)

        上面还涉及到了getNotificationClassName(notification) 获取这条通知中通过PendingIntent中设置的 Intent ,方法中用到了不对外使用的方法,代码如下:

 private String getNotificationClassName(Notification notification) {

        if (notification.contentIntent != null) {
            Intent intent = notification.contentIntent.getIntent();
            if (intent != null && intent.getComponent() != null) {
                return intent.getComponent().getClassName();
            }
        }
        return null;
    }

(3) 获取 PendingIntent 对象

         其中的 notification.contentIntent 是获取 通知中的 PendingIntent 对象,源码如下:

源码路径:/frameworks/base/core/java/android/app/Notification.java 

/**
     * 单击展开的状态条目时要执行的意图。
     */
    public PendingIntent contentIntent;
(4) PendingIntent.getIntent()

         接着再通过调用 PendingIntent 对象中的 getIntent() 来获取通知中设定的 Intent, 源码如下:

源码路径: /frameworks/base/core/java/android/app/PendingIntent.java

 /**
     * @hide (该方法不对外公开)
     * 返回 PendingIntent 中的 Intent .
     */
    @UnsupportedAppUsage
    public Intent getIntent() {
        try {
            return ActivityManager.getService()
                .getIntentForIntentSender(mTarget);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

 由于源码中有@hide,表明该方法不对第三方应用开放,所以如果是系统内置的应用,则可以使用.

(5) getNotificationTemplate(Notification notification) 

         Android中定义了一些通知模板,常用的如: BigPictureStyle , BigTextStyle 等,代码如下:

/**
 * 返回通知的类型,如果没有使用,则返回null.
 * 返回的类型,如: "android.app.Notification$BigTextStyle",
 * 因此需要对字符串进行截取,如最后返回: "BigTextStyle"
*/

private String getNotificationTemplate(Notification notification) {

        String template = notification.extras.getString(Notification.EXTRA_TEMPLATE);
        if (template != null) {
            int indexOf = template.indexOf('$');
            return template.substring(indexOf + 1);
        }
        return null;
    }

5. 通知的清除 

当通知被清除时,会调用 onNotificationRemoved(StatusBarNotification sbn) 方法,其中的参数 sbn 代表被删除的通知.可以在该方法里做一些删除后的工作.

6 . NotificationListenerService 中其他有用的方法

(1) 获取有效的通知 : getActiveNotifications() 

源码路径: /frameworks/base/core/java/android/service/notification/NotificationListenerService.java

/**
     * 请求未完成通知的列表(即那些对当前用户)。
     *
     * @return 活动通知数组,按自然顺序排序。
     */
    public StatusBarNotification[] getActiveNotifications() {
        StatusBarNotification[] activeNotifications = getActiveNotifications(null, TRIM_FULL);
        return activeNotifications != null ? activeNotifications : new StatusBarNotification[0];
    }

(2) 删除指定单条通知 : cancelNotification(String key)   

源码路径: /frameworks/base/core/java/android/service/notification/NotificationListenerService.java 

/**
     * 删除指定的一条通知
     *
     */
    public final void cancelNotification(String key) {
        if (!isBound()) return;//是否绑定了NotificationListenerService服务
        try {
            getNotificationInterface().cancelNotificationsFromListener(mWrapper,
                    new String[] { key });
        } catch (android.os.RemoteException ex) {
            Log.v(TAG, "Unable to contact notification manager", ex);
        }
    }

 (3) 删除指定的多条通知: cancelNotifications(String[] keys)

源码路径: /frameworks/base/core/java/android/service/notification/NotificationListenerService.java 

/**
     * 删除 数组 keys 中指定key的通知
     */
    public final void cancelNotifications(String[] keys) {
        if (!isBound()) return;
        try {
            getNotificationInterface().cancelNotificationsFromListener(mWrapper, keys);
        } catch (android.os.RemoteException ex) {
            Log.v(TAG, "Unable to contact notification manager", ex);
        }
    }

(4) 清除所有通知,对应于通知列表下的 清除所有通知的按钮功能: cancelAllNotifications()

  /**
     * 通知通知管理器清除所有通知
     * 类似于Android状态栏和通知面板调用 UI 的“全部关闭”功能
     * 收到通知后,通知管理器实际上会删除所有活动通知
     * 并且收到多个 {@link #onNotificationRemoved(StatusBarNotification)} 回调。
     */
    public final void cancelAllNotifications() {
        cancelNotifications(null /*all*/);
    }

至此,关于监听系统通知介绍完毕,谢谢观看!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1426066.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity - 调节camera物理相机参数(HDRP)

在 “Hierarchy” 右键 -> Volume -> Global Volume new 一个 profile, 设置Mode为Pysical Camera 再点击camera组件,这时候设置 ISO、Shutter Speed、Aperture等参数值还会有效。

[R] Why data manipulation is crucial and sensitive?

What does a data scientist really do? Identifying the pattern in cultural consumption, making fancy graph, engage a dialogue between data and the existing literature, refining hypothesis….(done within one months with three to four online meetings with p…

漏洞01-目录遍历漏洞/敏感信息泄露/URL重定向

目录遍历漏洞/敏感信息泄露/URL重定向 文章目录 目录遍历敏感信息泄露URL重定向 目录遍历 敏感信息泄露 于后台人员的疏忽或者不当的设计,导致不应该被前端用户看到的数据被轻易的访问到。 比如: ---通过访问url下的目录,可以直接列出目录下…

【实战】使用Helm在K8S集群安装MySQL主从

文章目录 前言技术积累什么是HelmStorageClass使用的工具版本 helm 安装 MySQL 1主2从1. 添加 bitnami 的仓库2. 查询 MySQL 资源3. 拉取 MySQL chart 到本地4. 对chart 本地 values-test.yaml 修改5. 对本地 templates 模板 修改6. 安装 MySQL 集群7. 查看部署的 MySQL 集群8.…

算法--数论

这里写目录标题 质数(素数)定义判断是否为质数暴力写法,试除法基本思想具体写法 优化基本思想(时间复杂度根号n)具体写法 分解质因数分析题意暴力写法基本思想具体代码 优化基本思想(时间复杂度小于等于根号…

聊聊ClickHouse MergeTree引擎的固定/自适应索引粒度

前言 我们在刚开始学习ClickHouse的MergeTree引擎时,就会发现建表语句的末尾总会有SETTINGS index_granularity 8192这句话(其实不写也可以),表示索引粒度为8192。在每个data part中,索引粒度参数的含义有二&#xf…

Camera | 15.闪光灯SGM3141概述

芯片说明 SGM3141是一种电流调节降压/升压电荷泵LED驱动器,能够驱动700M输出电流。它非常适合为相机闪光灯应用的高亮度LED供电。SGM3141具有1/2操作模式,用于控制闪光和火炬模式的输出电流。 电源电压在2.7V到5.5V之间工作,非常适合由1芯锂…

CDS view与替代对象

一,简介 替代对象是指用一个CDS view指派给一个透明表或常规数据库视图,使得透明表或常规数据库视图的访问重定向到该CDS view。 替代有诸多要求: 字段数量一致且同名对应,顺序可以不一致对应的字段数据类型长度等必须一致CDS v…

文心一言APP上线新功能,一张照片、三句话即可生成专属数字分身

只需一张照片、录制三句话,就能拥有一个自己的数字分身?这不是科幻电影,而是文心一言APP上线的新功能 - 数字分身。 目前,文心一言APP正在内测数字分身新功能,明天起,iOS和Android用户升级新版本后&#xf…

超简单设置Windows共享文件夹,传输文件无烦恼

前言 开始之前,先让小白感叹一下科技发展真快呀!(这句话纯粹是为了凑点字数) 随着科技的发展,人们手上总会有各种各样的电子设备:电脑、平板、手机、游戏机、电视盒子等等~ 有时候想要传输个文…

【Docker】【深度学习算法】在Docker中使用gunicorn启动多个并行算法服务,优化算法服务:从单进程到并行化

文章目录 优化算法服务:从单进程到并行化单个服务架构多并行服务架构Docker化并指定并行服务数量 扩展知识 优化算法服务:从单进程到并行化 在实际应用中,单个算法服务的并发能力可能无法满足需求。为了提高性能和并发处理能力,我…

MySQL基础(三)-学习笔记

一.innodb引擎: 1). 表空间:表空间是InnoDB存储引擎逻辑结构的最高层,启用了参数 innodb_file_per_table(在 8.0版本中默认开启) ,则每张表都会有一个表空间(xxx.ibd),一个mysql实例可以对应多个…

figure方法详解之清除图形内容

figure方法详解之清除图形内容 一 clf():二 clear():三 clear()方法和clf()方法的区别: 前言 Hello 大家好!我是甜美的江。 在数据可视化中,Matplotlib 是一个功能强大且广泛使用的库,它提供了各种方法来创建高质量的图形。在 Mat…

p2Cache: Exploring Tiered Memory for In-Kernel File Systems Caching——论文泛读

ATC 2023 Paper 分布式元数据论文汇总 问题 快速、字节寻址的持久性内存(PM)正在产品中变得越来越现实。然而,使传统的内核文件系统完全支持PM需要大量的工作,面临着在块级访问粒度和字节寻址之间转换的挑战。此外,新…

react 之 react.memo

React.memo 作用:允许组件在props没有改变的情况下跳过重新渲染 组件默认的渲染机制 默认机制:顶层组件发生重新渲染,这个组件树的子级组件都会被重新渲染 // memo // 作用:允许组件在props没有改变的情况下跳过重新渲染import…

UGUI中Text和TextMeshPro实现图文混排方式

一些项目中实现图文混排是自定义一个脚本去继承Text类,然后文本中用富文本的方式进行图片和超链接的定义,在代码中用正则表达式匹配的方式把文本中图片和超链接给替换,如下: TextMeshPro实现是生成SpriteAsset进行图文混排的&…

SpringCloud + Nacos配置文件加载顺序和优先级详解

文章目录 一、加载顺序与优先级1. 示例配置2. 配置文件分类3. 加载顺序4. 优先级 二、本地配置优先的设置结论 在微服务架构中,合理地管理和理解配置文件的加载顺序与优先级对于确保应用的稳定性和灵活性至关重要。特别是在使用 Spring Cloud Alibaba Nacos 作为配置…

数组与字符串深度巩固

经过再三思考觉得今天就写一篇关于数组与字符串相关的文章吧!其中字符串主要通过练习来巩固知识亦或是获得新知识。好接下来将进行我们的学习时刻了。 首先我们来思考一个问题,你真的了解数组的数组名吗?数组名真的就单单一个名字而已吗&…

nodejs+vue+mysql校园失物招领网站38tp1

本高校失物招领平台是为了提高用户查阅信息的效率和管理人员管理信息的工作效率,可以快速存储大量数据,还有信息检索功能,这大大的满足了用户和管理员这两者的需求。操作简单易懂,合理分析各个模块的功能,尽可能优化界…

【unity小技巧】unity3d创建和实现破碎打破物品,万物可破碎

文章目录 破碎插件可破碎的物品代码控制加入破坏力完结 破碎插件 关于物品破碎,其实之前已经分享过一个免费插件,如果没有碎片化的模型,可以选择使用这个插件: OpenFracture插件实现unity3d物体破裂和切割 可破碎的物品 代码控制…