查看: 90|回复: 1

HarmonyOS 6.1.1通知沙箱自定义铃声与wantAgent时态检索实战

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
在HarmonyOS NEXT 6.1.1(API 24)中,Notification Kit新增了两项实用特性:支持应用将非预置音频文件作为通知铃声(需存放在EL1沙箱files目录),以及开放了getNotificationParameters接口用于逆向检索已发布通知携带的wantAgent参数。本文通过一个黑金风格的控制舱Demo,详细介绍这两项特性的实现原理、核心API使用方式以及常见踩坑点。

### 一、沙箱自定义铃声:安全边界与uri::协议

在API 12时代,自定义铃声只能将音频文件硬编码在resources/rawfile目录下。对于需要根据用户动态选择或下载铃声的场景(如协同办公自定义联系人提示音、音乐APP录制音频设为日程提醒),这种方式不够灵活。6.1.1彻底放通了非预置音频文件作为通知铃声的链路,但为了安全防越权,系统做了严格的物理隔离约束:

- 音频文件必须放在应用沙箱的EL1(设备级加密区)的files目录或其子目录下。EL1目录在设备启动时即解密,即使锁屏状态下系统通知服务也能正常读取。若放在EL2(用户级加密区),锁屏时系统会因无法解密导致播放失败或回退为默认提示音。
- 在发布通知时,NotificationRequest的sound字段必须以“uri::”作为协议前缀,即:let soundFile = 'uri::' + fileUri.getUriFromPath(sandboxFilePath);

### 二、wantAgent时态检索:getNotificationParameters实战

现代鸿蒙应用频繁使用wantAgent承载通知点击后的跳转意图。6.1.1开放了notificationManager.getNotificationParameters(id, label?)方法,允许Stage模型下的主应用获取当前处于Active状态的通知所持有的wantAgent快照信息(如目标bundleName、abilityName、flags等)。

注意事项:
- 该API是时态检索,仅当通知还在通知栏中(锁屏、悬挂或下拉通知中心)时可查询。若用户手动清除或应用主动cancel该通知,调用时会抛出错误码1600007(The notification does not exist)。
- 实际开发中需要搭配BusinessError捕获,并在底层模块未就绪时进行降级处理(如使用仿真数据)。

### 三、核心代码实现

以下为Demo中主页面NotificationKitEnhanceDetail.ets的关键片段,展示了沙箱文件拷贝、铃声URI组装、通知发布以及参数检索的完整流程。
  1. import { router } from '@kit.ArkUI';
  2. import { hilog } from '@kit.PerformanceAnalysisKit';
  3. import { BusinessError } from '@kit.BasicServicesKit';
  4. import { notificationManager } from '@kit.NotificationKit';
  5. import { contextConstant, common } from '@kit.AbilityKit';
  6. import { fileIo as fs, fileUri } from '@kit.CoreFileKit';
  7. const TAG = 'NotificationKitEnhanceDetail';
  8. const SOUND_FILE_NAME = 'ringtone_demo.mp3';
  9. // 准备沙箱铃声:必须放在EL1 files目录下
  10. private prepareSandboxRingtone() {
  11.     try {
  12.         const context = getContext(this) as common.UIAbilityContext;
  13.         const applicationContext = context.getApplicationContext();
  14.         applicationContext.area = contextConstant.AreaMode.EL1;
  15.         const sandboxDir = applicationContext.filesDir;
  16.         const sandboxFilePath = sandboxDir + '/' + SOUND_FILE_NAME;
  17.         
  18.         // 读取rawfile资源并写入沙箱(若资源不存在则写入模拟MP3头部)
  19.         let fileData: Uint8Array;
  20.         try {
  21.             fileData = context.resourceManager.getRawFileContentSync(SOUND_FILE_NAME);
  22.         } catch (err) {
  23.             fileData = new Uint8Array([0x49, 0x44, 0x33, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
  24.         }
  25.         if (!fs.accessSync(sandboxDir)) {
  26.             fs.mkdirSync(sandboxDir, true);
  27.         }
  28.         const file = fs.openSync(sandboxFilePath, fs.OpenMode.CREATE | fs.OpenMode.WRITE_ONLY | fs.OpenMode.TRUNC);
  29.         fs.writeSync(file.fd, fileData.buffer);
  30.         fs.closeSync(file);
  31.         
  32.         // 获取FileUri并组装为uri::协议格式
  33.         let rawUri = fileUri.getUriFromPath(sandboxFilePath);
  34.         this.sandboxFileUriStr = 'uri::' + rawUri;
  35.     } catch (error) {
  36.         const err = error as BusinessError;
  37.         // 错误处理
  38.     }
  39. }
  40. // 发布通知:根据selectedRingtoneMode选择不同铃声源
  41. publishCustomNotification() {
  42.     let soundFile = '';
  43.     if (this.selectedRingtoneMode === 0) {
  44.         soundFile = ''; // 系统默认
  45.     } else if (this.selectedRingtoneMode === 1) {
  46.         soundFile = SOUND_FILE_NAME; // rawfile内置
  47.     } else {
  48.         soundFile = this.sandboxFileUriStr; // API 24沙箱
  49.     }
  50.    
  51.     let notificationRequest: notificationManager.NotificationRequest = {
  52.         id: this.currentNotificationId,
  53.         label: this.customNotificationLabel,
  54.         notificationSlotType: notificationManager.SlotType.SOCIAL_COMMUNICATION,
  55.         content: {
  56.             notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
  57.             normal: {
  58.                 title: '安全总线指令',
  59.                 text: `通知铃声已切换,当前校验模式: ${this.selectedRingtoneMode === 2 ? '沙箱文件' : '常规模式'}`,
  60.                 additionalText: 'API 24 通知特性测试'
  61.             }
  62.         },
  63.         sound: soundFile,
  64.         wantAgent: { toString: () => 'wantAgent::AllKitSocialIntentHolder' }
  65.     };
  66.    
  67.     notificationManager.publish(notificationRequest).then(() => {
  68.         // 成功处理
  69.     }).catch((err: BusinessError) => {
  70.         // 失败处理
  71.     });
  72. }
  73. // 检索wantAgent参数
  74. queryWantAgentParameters() {
  75.     setTimeout(() => {
  76.         notificationManager.getNotificationParameters(this.currentNotificationId, this.customNotificationLabel)
  77.         .then((data: notificationManager.NotificationParameters) => {
  78.             // 将data中的wantAgent信息转为JSON显示
  79.             this.queryResultJson = JSON.stringify(data, null, 2);
  80.         })
  81.         .catch((err: BusinessError) => {
  82.             // 若底层模块未就绪,使用仿真数据
  83.             this.queryResultJson = JSON.stringify({
  84.                 bundleName: 'com.example.harmonyos.allkit',
  85.                 abilityName: 'EntryAbility',
  86.                 flags: 32,
  87.                 extraInfo: '【离线仿真】wantAgent 意图拦截测试'
  88.             }, null, 2);
  89.         });
  90.     }, 400);
  91. }
复制代码

### 四、开发避坑指南

1. **EL1目录路径获取**:务必使用applicationContext.filesDir,且先设置area为EL1。如果误用其他目录(如databaseDir),锁屏下播放会失败。
2. **uri::前缀必须严格小写**:写成URI::或uri:都会导致系统无法识别。
3. **getNotificationParameters的时态性**:建议在用户点击查看通知或应用后台轮询时调用,并做好错误捕获(catch 1600007)。
4. **文件资源降级**:若沙箱文件不存在,记得提供优雅回退,例如播放系统默认铃声或提示用户设置。

通过上述实践,开发者可以快速将沙箱自定义铃声和wantAgent时态检索集成到自己的鸿蒙应用中,提升用户体验和安全性审计能力。
回复

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: HarmonyOS 6.1.1通知沙箱自定义铃声与wantAgent时态检索实战

感谢楼主的详细分享!沙箱自定义铃声和 wantAgent 时态检索这两个新特性确实很实用,特别是解决了动态音频文件做铃声的痛点。想请教一下,在 EL1 目录下拷贝音频文件时,如果用户从外部存储导入的文件,有没有推荐的安全校验方式?另外,getNotificationParameters 的时态检索在跨应用场景下(比如服务拉起另一个应用的通知),是否也能正常获取到 wantAgent 参数?期待后续更多实战分析!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-6-18 22:00 , Processed in 0.052388 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部