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

鸿蒙掌上驾考宝典应用开发49:鸿蒙推送服务——PushUtils 与通知管理

第49篇:鸿蒙推送服务——PushUtils 与通知管理

一、引言

推送服务是应用主动触达用户的重要渠道,用于发送考试提醒、学习通知、模考成绩等消息。DriverLicenseExam 项目通过鸿蒙推送服务实现了消息推送功能,包括通知权限申请、消息构建、推送发送、点击处理等完整流程。本文将深入解析推送服务的实现。

二、推送服务架构

2.1 推送流程

应用启动 │ ▼ 申请通知权限(requestEnableNotification) │ ▼ 权限已授权? ├── 否 → 不发送推送 │ └── 是 → 构建推送消息 │ ▼PushUtils.randomPushMessage()│ ▼ 系统通知栏显示 │ ▼ 用户点击通知 │ ▼EntryAbility.onNewWant()│ ▼ 解析参数 → 跳转到指定页面

2.2 推送相关文件

commons/commonLib/src/main/ets/push/├── Model.ets ← 推送数据模型 └── PushUtils.ets ← 推送工具类

三、推送权限管理

3.1 通知权限申请

在 EntryAbility 的onWindowStageCreate中申请通知权限:

//EntryAbility.ets notificationManager.requestEnableNotification(this.context).then(()=>{ hilog.info(0x0000,'testTag','[ANS] requestEnableNotification success'); }).catch((err: BusinessError)=>{ hilog.error(0x0000,'testTag','[ANS] requestEnableNotification failed, code: '+ err.code +', message: '+ err.message); });

3.2 权限检查

在发送推送前检查通知权限是否已开启:

// MainEntry.etssendPushNotice() {constisOn = notificationManager.isNotificationEnabledSync();if(isOn) {this.sendPushMessage(); } }

isNotificationEnabledSync()是同步方法,快速检查通知权限状态,避免在未授权时进行不必要的推送操作。

四、推送消息模型

4.1 推送参数定义

// PushUtils.etsexportinterfacePushActionParams{ picVideoUrl:string;// 图片/视频 URL(用于富媒体通知)title:string;// 推送标题id:string;// 推送 ID(用于去重和追踪)}

4.2 推送消息构建

// PushUtils.etsexportclassPushUtils{// 构建推送通知请求staticbuildNotificationRequest(params: PushActionParams): notificationManager.NotificationRequest{letnotificationRequest: notificationManager.NotificationRequest = { id: parseInt(params.id) ||0, content: { contentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, normal: { title:params.title, text:'点击查看详情', additionalText:params.picVideoUrl ||'', }, },// 点击通知后携带的参数wantAgent: {// 通过 Want 传递参数到 Abilitywant: { deviceId:'', bundleName:'qcjk.1.xxxxxx', abilityName:'EntryAbility', parameters: {params: JSON.stringify({ message:'practiceView', title:params.title, id:params.id, }), }, }, }, };returnnotificationRequest; } }

五、推送消息发送

5.1 随机推送消息

// PushUtils.etsstaticrandomPushMessage(params: PushActionParams, context: Context) {// 随机决定是否发送推送if(Math.random() >0.3) {// 30% 概率发送return; }constnotificationRequest =this.buildNotificationRequest(params); notificationManager.publish(notificationRequest) .then(() =>{Logger.info('PushUtils','Push notification published successfully'); }) .catch((err: BusinessError) =>{Logger.error('PushUtils','Failed to publish notification: '+ err.message); }); }

5.2 在主页面触发推送

// MainEntry.etsaboutToAppear(): void {this.bottomRectHeight = AppStorage.get('bottomRectHeight') ||0;this.vm.navStack.pushPathByName('splashPage',true);this.sendPushNotice();// 启动时尝试发送推送this.updateForm(0); } sendPushMessage() { let pushArticle: PushActionParams = { picVideoUrl:'', title:'驾考模板', id:'3445749589458989', }; PushUtils.randomPushMessage(pushArticle,this.getUIContext().getHostContext()asContext); }

六、推送点击处理

6.1 Want 参数解析

当用户点击通知栏的推送消息时,系统会通过 Want 参数将消息传递到 Ability:

// EntryAbility.ets - 处理推送点击onNewWant(want: Want,launchParam: AbilityConstant.LaunchParam): void { this.setLightOrDarkMode(this.context);Logger.info(TAG, 'Ability onNewWant');if(want.parameters&&want.parameters.params) {letparam: ESObject = {};try{ param =JSON.parse(want.parameters.paramsasstring); } catch (e) {Logger.error(TAG, 'Failedtoparse push params: ' +JSON.stringify(e)); }// 根据推送消息类型跳转到不同页面if(param.message==='practiceView') {// 跳转到模拟考试const examService =ExamService.instance(this.contextasContext); const par: ROUTE_PARAM = { title: '模拟考试',type:EXAM_MANAGER_TYPE.mock_exam, examManager: examService.getMockExamManager('模拟考试'), };CommonModel.instance.navStack.replacePathByName('practiceView',par); }elseif(param.message==='orderPractice') {// 跳转到顺序练习const param: ROUTE_PARAM = { title: '顺序练习',type:EXAM_MANAGER_TYPE.sequence, };CommonModel.instance.navStack.replacePathByName('practiceView',param); } }WantUtils.handlePushWant(want); this.shareServiceImpl.handleWant(want,this.context); }

6.2 冷启动与热启动处理

推送点击有两种场景:

  1. 冷启动:应用未运行,点击通知启动应用 → 在onCreate中处理
  2. 热启动:应用已在后台,点击通知唤醒应用 → 在onNewWant中处理
// 冷启动处理onCreate(want: Want,launchParam: AbilityConstant.LaunchParam){Logger.info(TAG, 'Ability onCreate');WantUtils.handlePushCall(want);// 处理冷启动推送this.shareServiceImpl.handleWant(want,this.context); }// 热启动处理onNewWant(want: Want,launchParam: AbilityConstant.LaunchParam): void {// 处理热启动推送WantUtils.handlePushWant(want); this.shareServiceImpl.handleWant(want,this.context); }

七、推送功能的扩展

7.1 本地通知

除了服务器推送,应用还可以发送本地通知,例如模拟考试完成后的成绩通知:

staticsendLocalNotification(title:string, content:string, context: Context) {constnotificationRequest: notificationManager.NotificationRequest= {id:Date.now(),content: {contentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,normal: {title: title,text: content, }, }, }; notificationManager.publish(notificationRequest) .then(() =>Logger.info('PushUtils','Local notification published')) .catch((err) =>Logger.error('PushUtils','Failed to publish: '+ err.message)); }

7.2 推送分类

不同类型的推送可以使用不同的通知渠道:

// 通知渠道分类const NOTIFICATION_CHANNELS = { EXAM_REMINDER: { id:'exam_reminder',name:'考试提醒',importance:4}, STUDY_TIP: { id:'study_tip',name:'学习建议',importance:3}, PROMOTION: { id:'promotion',name:'活动推广',importance:2}, };

八、总结

推送服务是应用与用户保持互动的重要渠道。DriverLicenseExam 项目通过完整的推送实现展示了:

  1. 权限管理:通知权限的申请和检查
  2. 消息构建:NotificationRequest 的消息结构
  3. 推送发送:通过 notificationManager.publish 发送
  4. 点击处理:通过 Want 参数传递,支持冷启动和热启动
  5. 页面跳转:根据推送类型跳转到不同页面

关键源码文件:

  • commons/commonLib/src/main/ets/push/PushUtils.ets— 推送工具类
  • commons/commonLib/src/main/ets/push/Model.ets— 推送数据模型
  • products/entry/src/main/ets/entryability/EntryAbility.ets— 推送点击处理
  • products/entry/src/main/ets/pages/MainEntry.ets— 推送触发入口
  • products/entry/src/main/ets/util/WantUtils.ets— Want 参数处理工具
http://www.cnnetsun.cn/news/4086421.html

相关文章:

  • 常用git指令
  • VBrowser-Android多线程下载原理:分片下载与文件合并的完整实现
  • CKAN模组管理终极指南:3步告别KSP手动装MOD的噩梦
  • ComfyUI 完整入门指南:从零打造可视化 AI 图像视频生成工作流
  • 游戏黑屏、显卡花屏查不出原因?5分钟一次显存检测就真相大白
  • 收藏!AI大模型人才抢手,小白也能抓住高薪机遇,小白必看!
  • 手写Zeal 8-bit OS设备驱动:从0到1实现键盘与串口驱动的完整教程
  • VBrowser-Android架构剖析:DownloadManager任务调度与前台下载服务
  • memtest_vulkan显存稳定性测试上手教程:5分钟揪出显卡“暗病“
  • WarcraftHelper:魔兽争霸3终极优化工具,三步免费解锁宽屏、高帧率与大地图
  • Esp-radio 硬件接线完全教程:ESP8266、VS1053 与 TFT 显示屏的详细接线图解析
  • Linux 网络接口命名规则
  • auto-value-parcel是什么?Android开发者告别手写Parcelable的终极利器
  • 三个平台一套手感:跨平台文本编辑器 Notepad-- 从安装到上手的实战笔记
  • 网页视频只能看不能存?N_m3u8DL-RE让流媒体下载一学就会
  • Esp-radio 硬件清单终极指南:DIY 网络收音机必需的 8 类元件选购建议
  • 代码评审看性能数据,先确认测试测到了什么
  • JoliCi 服务管理实战:一键启动 MySQL、Redis 等 10 种测试依赖服务
  • 百度ERNIE-Image本地部署指南:如何在ComfyUI中十几分钟跑通文生图模型
  • 一致性协议实现升级前的兼容性检查
  • 为什么选择 awesome-deepseek-agent?DeepSeek V4 接入的 10 大优势
  • Glance项目深度解读:macOS上最全能的Quick Look插件为何值得每个开发者安装
  • 参与Zeal 8-bit OS开源贡献:路线图、贡献规范与提PR完整指南
  • 探秘 babel-plugin-istanbul 源码:Babel 插件如何在编译期完成代码插桩
  • Parabolic视频下载工具完整上手指南:一个界面搞定200+网站的视频与音频下载
  • r3f-game-demo移动系统揭秘:Moveable组件如何实现基于瓦片的平滑移动与碰撞检测
  • terraform-provider-snowflake 用户与角色管理指南:构建企业级访问控制体系的 8 个步骤
  • 视频生成显存占用高怎么解决?LightVAE 与 LightTAE 让速度、画质、显存兼得
  • Drawnix 新手入门完整教程:界面布局与核心操作一网打尽
  • GreatSQL入门完全指南:开源免费金融级数据库的五大核心特性一网打尽