展区提醒换铃声后,HarmonyOS 6.1.1 Notification 沙箱铃声怎样让等待状态不误导用户
展区值守人员换好提醒铃声后,最常说的一句是“下一次应该会响”。这句话里混着三种不同的期待:声音文件是否已准备好、通知请求是否真正发出、设备是否已经在某一轮观察中让人听见。若页面只显示“设置成功”,用户就会把文件准备、发布返回和听觉结果连成一条不存在的完成链;到了下一次提醒没有声音时,也很难知道该从哪一层开始排查。
本页采用“文件准备 → 发布门禁 → 人工核验”的三段结构,并把通知可见、声音可听各自记录在一个验证轮次里。它解决的不是替展区判断人员是否接近,也不是自动确认声音效果,而是把“现在只是准备完成”“已经可以观察”“本轮无法判断”表达得足够清楚,让等待不再被误写成结果。
一、换铃声之后,用户真正想确认的是什么
1.1 “文件已准备”与“下一次会响”不是同一句话
用户点击“准备 EL1 文件”后,页面会从工程 rawfile 读取 article11_notice.wav,写到当前应用的 EL1 files 目录,并显示文件状态、源/目标字节和沙箱路径。完成这一段后,页面能说的是“EL1 文件已准备并完成大小核对”;它还不能说“展区提醒已具备可听效果”。
原因并不复杂:文件准备只解决了通知声音的一个输入条件。通知权限可能还未开启,声音 URI 也可能还未通过发布前门禁;即使这些条件都通过,设备的系统策略、媒体音量、输出通道和实际环境仍由后续观察决定。把“文件已准备”写得具体,是为了让用户既看到已完成的工作,也不误以为整条提醒链已经结束。

场景解说:本图待展示展区提醒页面的三段操作区、文件初始状态、发布门禁与人工核验入口。它能证明页面尚未形成任何验证结论,不能证明展区提醒会响。
1.2 页面应让用户看见自己正处于哪一段,而不是只看到一个大按钮
本工程把流程分成三个用户可见的区域:
- 准备声音文件:读取 rawfile、写入 EL1 files,并核对真实写入大小。
- 核对发布条件:同时显示通知授权、
fileUri、NotificationRequest.sound和发布门禁。 - 发布后人工核验:发布返回后,再分别填写“通知可见”和“声音可听”的人工结论。
这种分段不只是为了把界面做得整齐。它让用户在“没有听到”的时候先定位当前步骤:若还停在第一段,问题不能被称为通知未到;若第二段权限是 denied,就不应去追问设备是否静音;只有进入第三段,才谈得上“本轮通知看见了吗、声音听见了吗”。
对产品文案来说,最有帮助的不是统一写“正在处理中”,而是把等待对象说出来,例如“sound URI 待准备”“通知授权待核对”“等待人工分别核验通知可见与声音可听”。这样用户不需要记住底层调用顺序,也能知道下一步该停在哪里。
1.3 展区场景中的“提醒”也不能替代风险事实
本页用于验证沙箱铃声的配置和人工核验,通知文本本身只是页面给出的固定提示。它不连接真实展区人员位置、客流接近、文物风险或后台事件处置。因此,即便用户看见通知或真机听到声音,也只能证明当前设备上的通知链某一层有了观察;不能据此写“展区风险已发生”或“值守人员已经完成处置”。
把这种边界提前写出来,是为了避免用户把“换铃声”变成对现场风险的确认动作。通知可以帮助提醒,但提醒触发条件、人员接收情况和业务处置仍然需要各自的记录与证据。
二、从原始短音到 sound 字段,页面怎样让准备结果可复核
2.1 EL1 沙箱写入要同时留下路径和大小
工程准备声音时,明确把应用上下文切换到 EL1,再使用 filesDir 生成沙箱路径。随后读取 rawfile、写入目标文件、读取目标文件状态,并对照三种大小:源字节数、实际写入字节数和目标文件大小。
applicationContext.area = contextConstant.AreaMode.EL1;
const sandboxPath = `${applicationContext.filesDir}/${this.rawFileName}`;
const sourceBytes = await getContext(this).resourceManager.getRawFileContent(this.rawFileName);
const targetFile = fileIo.openSync(sandboxPath,
fileIo.OpenMode.WRITE_ONLY | fileIo.OpenMode.CREATE | fileIo.OpenMode.TRUNC);
const bytesWritten = fileIo.writeSync(targetFile.fd, sourceBytes.buffer as ArrayBuffer);
const targetStat = await fileIo.stat(sandboxPath);
这段代码能证明页面按当前运行时的应用目录准备了本地声音文件,并能取得源字节、写入字节与目标文件大小来做核对。它不能证明文件已经被系统通知读取,也不能证明扬声器、耳机或其他输出通道已经播放。
产品上应把路径和大小理解为“可回看配置”,不是“声音效果”。当用户换了铃声后只能看到一个勾选符号,下一位值守人员无从判断文件究竟有没有进沙箱;保留路径与大小后,至少能把“文件没准备好”和“等待听觉观察”分开处理。

场景解说:本图待展示准备 EL1 文件的入口、读取中的文件状态和源/目标字节。它能证明用户启动了本地文件准备,不能证明通知已发出。
2.2 大小核对失败时,结论应该停在“文件准备失败”
如果实际写入字节数或目标文件大小与原始资源不同,工程会中止后续流程,并将文件状态写为“EL1 文件准备失败”。在串行流程中,这会使自动状态停在“文件准备失败”,不会继续申请通知授权或调用发布。
这类失败不该被翻译成“自定义铃声不支持”或“用户设备静音”。页面目前证明的是一次文件准备没有通过大小核对;它没有检测到系统声音策略,也没有向通知服务发出本次请求。正确的用户出口是查看错误文本、重新准备文件或由有权限的人检查资源与应用目录,而不是开始一轮毫无依据的人工听觉核验。
2.3 uri:: 把本地路径变成发布前可检查的声音值
文件通过大小核对后,工程调用 fileUri.getUriFromPath(sandboxPath),并给结果加上 uri:: 前缀。isValidSound() 要求该值以 uri:: 开头,且不允许出现 ../ 或 /..:
const convertedFileUri = fileUri.getUriFromPath(sandboxPath);
const sound = `uri::${convertedFileUri}`;
if (!this.isValidSound(sound)) {
throw new Error(`sound URI 不合规:${sound}`);
}
this.fileUriValue = convertedFileUri;
this.soundValue = sound;
this.fileState = 'EL1 文件已准备并完成大小核对';
这段代码能证明页面在本地生成并检查用于 NotificationRequest.sound 的声音值。它不能证明通知已经发布,也不证明 URI 一旦通过就能绕开设备的系统策略。
对用户而言,页面不必把整串 URI 当作需要理解的“成功代码”,但要给出足够明确的状态:URI 待准备时,应留在文件准备;URI 通过后,才可以看通知授权。这样“换铃声”不再是一次模糊设置,而是一条能继续被核对的状态线。

场景解说:本图待展示 EL1 路径、fileUri、
NotificationRequest.sound与发布门禁。它能证明本地声音值可进入发布前检查,不能证明自定义铃声已经播放。
2.4 自动串行流程可以省操作,不能省略中间结论
页面进入后会调度一次“准备、授权、发布”的串行流程,用户也可以主动点击相同入口。它的作用是减少手动切换,不是把三个步骤压缩成一个“设置完成”。当文件准备失败时,流程停止并显示“串行流程停止:文件准备失败”;当权限未通过时,停止在“通知未授权”;只有发布 Promise 返回,状态才写为“串行流程完成:publish 已返回”。
因此,自动流程的最终状态应被当作“走到了哪一步”的摘要。它不等于通知中心可见,也不等于声音可听;页面后面仍要新建验证轮次,由人分别记录两种观察。把自动与人工的边界写清,能避免用户误以为后台已经替自己听过声音。
三、发布门禁通过后,页面怎样避免把等待写成送达
3.1 通知授权与声音 URI 必须同时满足
工程在发布前先检查沙箱路径与声音 URI。若路径仍为“尚未准备”或声音值不合规,页面将发布状态标为失败,并写明“请先成功准备 EL1 文件和 uri:: sound”。通过文件门槛后,工程再次读取系统通知开关;若权限未授予,则写入“通知权限未授予,未调用 publish”。
if (this.soundState.sandboxPath === '尚未准备' || !this.isValidSound(this.soundValue)) {
this.updatePublish('failed', '发布前校验失败:请先成功准备 EL1 文件和 uri:: sound。');
return;
}
const enabled = await notificationManager.isNotificationEnabled();
this.updatePermission(enabled ? 'granted' : 'denied', enabled ? '暂无错误' : '系统通知当前未启用');
if (!enabled) {
this.updatePublish('failed', '通知权限未授予,未调用 publish。');
return;
}
这段代码能证明页面将声音输入和系统通知授权作为两项并列门槛,并在其中任意一项不满足时明确停止发布。它不能证明权限 granted 后会在任何设备上听见声音,也不能证明展区人员已经收到提醒。
这时页面最好的反馈不是让用户再点一次“换铃声”,而是告诉他哪项门禁没过。文件问题应回到 EL1 准备区,权限问题应进入系统授权;将两者混成“提醒失败”,只会让用户重复做无关动作。
3.2 publish 返回创建的是“可观察起点”,不是完成终点
满足门禁后,工程将当前 soundValue 放入 NotificationRequest.sound,调用 notificationManager.publish(request)。当 Promise 成功返回时,页面把发布状态写为 published,并立刻创建一条验证轮次:通知可见与声音可听均初始化为 pending。
await notificationManager.publish(request);
this.updatePublish('published', '暂无错误');
const publishReturnedAt = this.now();
this.createVerificationRound(
publishReturnedAt,
'publish Promise 已成功返回,等待人工分别核验通知可见与声音可听。'
);
这段代码能证明本次发布调用已返回,并在页面中建立一轮以该返回时间为依据的人工核验。它不能证明通知中心已经可见,也不能证明设备已经播放了当前自定义铃声。
对用户来说,pending 不是失败,也不该变成绿色成功。它表达的是“现在已经有一个可观察对象,但还没有观察结果”。这个中间状态很关键:它让用户知道该去看系统界面或真机,而不是在页面里抢先确认。
3.3 本页保留“无法判断”,不是逼用户二选一
人工核验字段有三种状态:pending、confirmed 和 undetermined。其中 undetermined 在页面上显示为“无法判断”,适合设备不在身边、展区环境过于嘈杂、系统界面暂时无法查看等情况。记录这项状态时,页面会把结论写为“无法判断,待补系统或听觉证据”,而不是把它当成“未听见”或“发布失败”。
这避免了一个常见误导:用户只有“已确认”和“失败”两个按钮时,往往会在没有条件观察时随便选一项以结束流程。保留“无法判断”让页面诚实记录当前缺口,也让下一位值守人员看得出需要补的是通知中心观察还是听觉观察。

四、为什么同一次发布还需要多个验证轮次
4.1 一轮核验只描述一次观察,不会修改已发生的发布
页面每次发布成功后新建一条验证轮次,记录轮次编号、启动时间、发布返回时间、通知可见状态、声音可听状态和事件记录。用户之后点击“开始新的验证轮次”,工程会引用最近成功发布的返回时间新建一轮,但明确写入“未重新发布通知”。
this.createVerificationRound(
this.verificationRounds[0].publishReturnedAt,
'基于既有成功发布返回开始新的人工核验轮次;未重新发布通知。'
);
this.markOperation('已开始新的会话内人工核验轮次');
这段代码能证明页面允许用户围绕已有发布返回重新开始人工观察,并且把“新轮次”与“重新发布”分开。它不能证明之前的通知仍在通知中心展示,也不能证明新一轮观察发生了新的声音播放。
这个设计适合展区交班场景。白天值守人员可能因设备不在身边而标记“无法判断”,夜班人员拿到真机后需要重新观察;他们应新开一轮记录自己的观察条件,而不是覆盖白班的结论,或误点击发布造成重复提醒。
4.2 多轮次解决的是观察时间差,不是把一次结果变成永久事实
不同轮次可以有不同的“通知可见”或“声音可听”结论,但它们都必须带着各自的启动时间和相同的发布返回依据。用户在阅读时应先看当前激活轮次,再看该轮的事件记录,而不是把历史轮次中某个“已确认”直接当作本次展区状态。
例如第一轮在安静环境中确认声音可听,第二轮换到另一台设备时仍可能无法判断;这两条记录并不矛盾,因为它们说明的是不同观察条件下的人工感知。页面不读取勿扰、通知渠道或媒体音量,因此也不会用程序自动替用户解释两个结果为何不同。
这就是轮次设计对产品的价值:它不制造一个看似永久的“铃声正常”结论,而是留下每一次观察的时间与缺口,支持后续的人继续补证,而非凭记忆覆盖。
4.3 轮次中的两项人工结论必须分开填写
通知可见与声音可听在同一轮次中并列,但它们是两个独立字段。用户可以确认通知中心可见,而仍保留声音“待确认”;也可以确认听见声音,但没有权限查看通知中心时将可见性保留为“无法判断”。
页面为两个字段分别写入事件记录,并把“已人工确认”或“无法判断,待补系统或听觉证据”保留在当前轮次中。它避免把“我听见了”偷换成“通知中心一定可见”,也避免把“我看见通知了”偷换成“当前自定义铃声一定被播放”。
五、用户在等待时,怎样把状态留给下一位值守人员
5.1 等待并不是空白状态,应该留下当前缺的证据
当文件已准备、权限已通过、publish 已返回,但用户暂时无法确认通知或声音时,页面应保留当前轮次编号、轮次启动时间、发布返回时间、通知可见状态和声音可听状态。它们共同说明“有一项发布返回可以观察,但本轮还缺人工结论”。
值守人员不必为了填满表单而把 pending 改成 confirmed。如果系统界面尚未打开、设备不在身边或环境无法听辨,保留“待确认”或“无法判断”比写一条错误的成功记录更能帮助后续处理。等待状态的价值就在于清楚标出缺口,而不是假装没有任何信息。
5.2 推荐的交接摘要要区分配置、发布与观察
展区值守交接时,可按下面顺序记录,避免只写一句“铃声已换”:
- 配置层:EL1 文件是否完成大小核对,
fileUri和sound是否已准备。 - 门禁层:通知权限是否为
granted,发布请求是否真的返回,或在哪个门禁被阻止。 - 观察层:当前验证轮次与发布时间是什么,通知可见、声音可听分别是待确认、已确认还是无法判断。
- 现场边界:本页只记录提醒链;展区接近风险、人员阅读和处置结果仍需独立业务记录。
一条可用的摘要可以是:“EL1 声音文件与 uri:: 已准备,通知权限已核对,本次 publish 已返回并创建第 2 轮人工核验;通知可见待确认,声音可听无法判断,待真机与系统界面补证;本页未记录展区风险或人员处置结论。”这段话不会代替人工验证,却能让接手的人准确进入尚未完成的那一层。
5.3 发生失败时,回到对应门禁,而不是覆盖观察记录
若文件准备失败,应回到 rawfile 与 EL1 写入的错误;若通知未授权,应先处理系统开关;若 publish 返回失败,应保留失败文本并停止建立人工核验。只有已有成功发布记录时,页面才允许开始验证轮次。
这样的回退路径避免一个常见问题:用户在发布失败后仍然去填写“声音可听:无法判断”,使页面看起来像已有待观察结果。实际上,缺的是发布返回,不是听觉证据。错误应停在发生它的层级,页面才不会把未开始的观察伪装成一段已完成的流程。
必要条件|运行门禁
G1:SDK/API门禁
确认 HarmonyOS 6.1.1 API 24 已安装,Hvigor 能构建 entry 模块。


G2:Kit门禁
确认本文页面的 Kit import 可解析,并使用 API 24 支持的接口。
G3:模块/页面门禁
确认 Stage 模块、页面路由、设备类型和相关模块配置完整。
G4:权限门禁
确认静态声明存在;Camera/AI字幕等运行时能力在真正调用前完成动态授权。

G5:系统能力门禁
确认目标设备声明并实际提供所需摄像头、麦克风、地图、视觉或文件能力。任一门禁未通过,停止进入核心操作。

MapKit文章在 G5 放行前增加服务配置门禁:AppGallery Connect 中已选择正确项目,应用包名和签名证书与工程一致,MapKit 服务已开通且应用服务凭据/授权配置已完成。不得在文章或源码中暴露服务密钥。



更多推荐


所有评论(0)