当前位置: 首页 > news >正文

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

1. 需求

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

2. NotificationListenerService 接口

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

源码路径 : /frameworks/base/core/java/android/service/notification/NotificationListenerService.javapublic abstract class NotificationListenerService extends Service {......

3. 实现 NotificationListenerService

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

public class MyNotificationListenerService extends NotificationListenerService {//当系统收到新的通知时,会触发该接口@Overridepublic void onNotificationPosted(StatusBarNotification sbn) {addAlienNotificationInfo(sbn); //获取通知的内容}//当系统移除通知时,即在通知列表中清除通知时,或者卸载应用时,该应用包名下的通知都会被清除,也同样会会触发该接口@Overridepublic 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;//通知的时间//通过下面的方法也可以查看通知中的设置的全部参数for(String mykey : notification.extras.keySet()){String ex = " " + mykey +" => " + notification.extras.get(mykey)+ ";";Log.d(TAG,"ex="+ex);}
}

上面在获取通知的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";

上面还涉及到了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;}

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

源码路径:/frameworks/base/core/java/android/app/Notification.java /*** 单击展开的状态条目时要执行的意图。*/public PendingIntent contentIntent;

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

源码路径: /frameworks/base/core/java/android/app/PendingIntent.java/*** @hide (该方法不对外公开)* 返回 PendingIntent 中的 Intent .*/@UnsupportedAppUsagepublic Intent getIntent() {try {return ActivityManager.getService().getIntentForIntentSender(mTarget);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}

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

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*/);}

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

相关文章:

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

1. 需求 在系统内置应用中或者在第三方应用中,获取Android系统收到的通知的内容. 2. NotificationListenerService 接口 Android 系统预留了专门的API, 即 NotificationListenerService 接口,它的源码路径为: 源码路径 : /frameworks/base/core/java/android/service/notifi…...

SpringBoot+Redis如何实现用户输入错误密码后限制登录(含源码)

点击下载《SpringBootRedis如何实现用户输入错误密码后限制登录(含源码)》 1. 引言 在当今的网络环境中,保障用户账户的安全性是非常重要的。为了防止暴力破解和恶意攻击,我们需要在用户尝试登录失败一定次数后限制其登录。这不…...

kotlin中的初始化问题纪录

1. init 代码块的顺序问题 init代码块和成员变量实质上是按先后顺序执行的。若果init{} 中有成员变量使用。要把成员变量放到代码块之前。 2. init代码块之中的函数问题 下面是一段错误的代码: class mkotlin{val info:Stringinit {getInfoMethod()info "adad…...

Web中的转发与重定向

转发与重定向 一、转发和重定向的概念1.转发2.重定向 二、JavaWeb 中的转发和重定向三、SpringMVC 中的转发和重定向1.转发(1) 默认的方式(2) 完整的方式 2.重定向 四、总结 一、转发和重定向的概念 在 Web 应用中,转发和重定向都是用于将请求从一个页面传递到另一…...

交叉注意力融合时域、频域特征的FFT + CNN-Transformer-CrossAttention轴承故障识别模型

目录 往期精彩内容: 前言 1 快速傅里叶变换FFT原理介绍 第一步,导入部分数据 第二步,故障信号可视化 第三步,故障信号经过FFT可视化 2 轴承故障数据的预处理 2.1 导入数据 2.2 制作数据集和对应标签 3 交叉注意力机制 …...

STM32读取MPU6050数据并通过角度值控制舵机运动(STM32、GY-521 MPU6050、SG90舵机、MG946舵机)

通过STM32F103C8T6读取MPU6050数据控制舵机运动(STM32、GY-521 MPU6050、SG90舵机、MG946舵机) 最终现象一、MPU6050数据读取二、舵机控制原理①什么是PWM?②STM32F103C8T6如何生成PWM?③控制舵机需要什么样的PWM波? 三…...

Unity_Playable工具使用

Unity_Playable工具使用 目录 Unity_Playable工具使用 1. Default Playables(Timeline扩展) 2. PlayableGraph Visualizer&#x...

Flutter canvas 画一条波浪线 进度条

之前用 Flutter Canvas 画过一个三角三角形,html 的 Canvas 也画过一次类似的, 今天用 Flutter Canvas 试了下 感觉差不多: html 版本 大致效果如下: 思路和 html 实现的类似: 也就是找出点的位置,使用二阶…...

Java技术栈 —— Spring MVC 与 Spring Boot

参考文章或视频链接[1] Spring vs. Spring Boot vs. Spring MVC[2] Key Differences Between Spring vs Spring Boot vs Spring MVC...

跟着cherno手搓游戏引擎【16】Camera和Uniform变量的封装

相机封装&#xff1a; OrthographicCamera.h: #pragma once #include <glm/glm.hpp> namespace YOTO {class OrthographicCamera{public:OrthographicCamera(float left,float right , float bottom,float top);const glm::vec3& GetPosition()const { return m_Pos…...

微服务中间件 RabbitMq学习

1、为什么需要Mq 例如在用户注册业务中&#xff0c;用户注册成功后 需要发注册邮件和注册短信&#xff0c;传统的做法有两种 1.串行的方式&#xff1b;2.并行的方式 &#xff1b; 假设三个业务节点分别使用50ms&#xff0c;串行方式使用时间150ms&#xff0c;并行使用时间10…...

3D Gaussian Splatting-实时辐射场渲染技术

引用自&#xff1a;https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/3d_gaussian_splatting_high.pdf 概述&#xff1a; 该论文介绍了一种用于实时辐射场渲染的3D高斯点渲染技术。 其基本原理是&#xff1a; 一&#xff1a;首先从SfM校准的图像及其对应的稀疏点云…...

vue中nextTick()

在 Vue.js 中&#xff0c;nextTick() 是一个非常有用的方法&#xff0c;用于在下一个 DOM 更新循环结束后执行延迟回调。这在你需要读取或写入刚刚更新的 DOM 时非常有用。 下面是一个简单的示例代码&#xff0c;用于解析 nextTick() 的用法&#xff1a; <template> &…...

Redis 布隆过滤器

布隆过滤器 这一篇文章主要是记录布隆过滤器的使用和认识 主要参考了如下的blog https://blog.csdn.net/weixin_42972832/article/details/131211665 他讲的还不错 简单的来说,布隆过滤器,实际上就像是一个集合,拿redis的key来举例来说,布隆过滤器的设置就是去过滤不属于redi…...

中国的茶文化:现代生活中的茶文化

中国的茶文化&#xff1a;现代生活中的茶文化 引言 在现代社会的快节奏生活中&#xff0c;茶文化并未随时间流逝而褪色&#xff0c;反而以其独特的方式融入了全球各地人们的日常生活。它超越了饮品本身的范畴&#xff0c;成为一种连接历史、人文与现代生活方式的艺术形式。本文…...

Python正则表达式语法

正则表达式是一种强大的文本处理工具&#xff0c;它可以用来搜索、匹配和替换特定的字符模式。在Python中&#xff0c;正则表达式常常被用于处理字符串数据&#xff0c;例如文本搜索、数据提取、格式验证等任务。本文将深入介绍Python中正则表达式的语法&#xff0c;帮助读者全…...

C++核心编程:文件操作 笔记

5.文件操作 程序运行时产生的数据都属于临时数据&#xff0c;程序一旦允许结束都会被释放。通过文件可以将数据持久化 C中对文件操作需要包含头文件<fstream> 文件类型分为两种&#xff1a; 文本文件 - 文件以文本的ASCII码形式存储在计算机中二进制文件 - 文件以文本…...

ElementUI组件:Button 按钮

ElementUI安装与使用指南 Button按钮 点击下载learnelementuispringboot项目源码 效果图 el-button.vue页面效果图 项目里el-button.vue代码 <script> export default {name: "el_button",// 注意这里的名称不能和 router inex.js里的name一样methods: {s…...

#RAG|NLP|Jieba|PDF2WORD# pdf转word-换行问题

文档在生成PDF时,文宁都发生了什么。本文讲解了配置对象、resources对象和content对象的作用,以及字体、宇号、坐标、文本摆放等过程。同时,还解释了为什么PDF转word或转文字都是一行一行的以及为什么页眉页脚的问题会加大识别难度。最后提到了文本的编码和PDF中缺少文档结构标…...

solr的原理是什么

1 Java程序里如果有无限for循环的代码导致CPU负载超高&#xff0c;如何排查&#xff1f; 排查Java程序中由于无限循环导致的CPU负载过高的问题&#xff0c;可以按照以下步骤进行&#xff1a; 资源监控&#xff1a; 使用系统命令行工具&#xff08;如Linux上的top或htop&#xf…...

ESP32开发环境:VS Code与ESP-IDF插件高效配置指南

1. 为什么选择VS Code开发ESP32&#xff1f; 第一次接触ESP32开发时&#xff0c;我尝试过各种开发工具&#xff1a;Arduino IDE、PlatformIO、Eclipse...最后发现VS Code配合ESP-IDF插件才是最佳组合。这个方案不仅免费开源&#xff0c;更重要的是能充分发挥ESP32的全部性能特…...

深入浅出MIPI D-PHY:对比HS高速模式与LP低功耗模式,揭秘手机摄像头省电又流畅的底层原理

解密MIPI D-PHY&#xff1a;手机摄像头如何实现高速与低功耗的完美平衡 当你用手机拍摄4K视频时&#xff0c;是否想过为什么画面如此流畅&#xff0c;而电量消耗却相对可控&#xff1f;这背后隐藏着一项关键技术——MIPI D-PHY物理层协议。作为现代移动设备图像传输的核心通道&…...

NVIDIA Orin AGX 开发环境快速部署指南

1. 开箱即用&#xff1a;NVIDIA Orin AGX开发环境全景概览 拿到NVIDIA Orin AGX开发板的第一天&#xff0c;我盯着这个黑色的小盒子看了十分钟——它看起来像块普通电路板&#xff0c;但内核却是当前最强的边缘计算芯片之一。作为过来人&#xff0c;我理解新手面对这块板子时的…...

Next-MDX-Remote部署指南:从开发到生产环境的完整流程

Next-MDX-Remote部署指南&#xff1a;从开发到生产环境的完整流程 【免费下载链接】next-mdx-remote Load mdx content from anywhere through getStaticProps in next.js 项目地址: https://gitcode.com/gh_mirrors/ne/next-mdx-remote Next-MDX-Remote 是一款强大的 N…...

Beyond Compare 5密钥生成终极指南:轻松解决评估模式错误

Beyond Compare 5密钥生成终极指南&#xff1a;轻松解决评估模式错误 【免费下载链接】BCompare_Keygen Keygen for BCompare 5 项目地址: https://gitcode.com/gh_mirrors/bc/BCompare_Keygen 你是否曾遇到Beyond Compare 5弹出"评估模式错误"的困扰&#xf…...

智能票务自动化工具:提升大型活动门票获取效率的全流程解决方案

智能票务自动化工具&#xff1a;提升大型活动门票获取效率的全流程解决方案 【免费下载链接】Automatic_ticket_purchase 大麦网抢票脚本 项目地址: https://gitcode.com/GitHub_Trending/au/Automatic_ticket_purchase 在数字化时代&#xff0c;大型展会、体育赛事等热…...

从ATE到RPE:用evo全面解读你的SLAM算法在KITTI上的表现

从ATE到RPE&#xff1a;用evo全面解读你的SLAM算法在KITTI上的表现 在SLAM算法开发中&#xff0c;量化评估是验证算法性能的关键环节。KITTI数据集作为自动驾驶领域最具影响力的基准测试平台之一&#xff0c;为研究者提供了丰富的真实场景数据。但如何从海量轨迹数据中提取有价…...

UI-TARS-desktop场景应用:自动生成销售报告与更新库存实战

UI-TARS-desktop场景应用&#xff1a;自动生成销售报告与更新库存实战 1. 场景痛点与解决方案 1.1 传统销售管理的效率瓶颈 在零售和电商行业中&#xff0c;销售数据分析和库存管理是日常运营的核心工作。传统方式通常需要&#xff1a; 手动从多个系统导出销售数据人工整理…...

158页精品PPT | 某大型研发制造集团信息化IT规划整体方案

许多公司在数字化转型过程中会遇到一些共同的挑战&#xff0c;比如数据孤岛、技术更新慢、员工技能不足等。这些问题会导致企业效率低下&#xff0c;难以适应市场变化。针对这些问题&#xff0c;我们提出了一套解决方案&#xff0c;核心目标是帮助企业提升数字化水平&#xff0…...

城通网盘限速破解:ctfileGet让下载效率提升10倍的技术革命

城通网盘限速破解&#xff1a;ctfileGet让下载效率提升10倍的技术革命 【免费下载链接】ctfileGet 获取城通网盘一次性直连地址 项目地址: https://gitcode.com/gh_mirrors/ct/ctfileGet 在数字化协作日益频繁的今天&#xff0c;网盘已成为信息传递的重要枢纽。然而城通…...