
首发于华为开发者论坛https://developer.huawei.com/consumer/cn/blog/topic/03226498246684304提醒、通知、日历事件这类功能结果是系统侧异步兑现的所以 API 的返回值说的是「请求已受理」不是「事情已发生」。我把这两句话当成了一句话同一个坑连踩了三次。三次都没有报错没有异常没有一行红色日志。能拿出来的事故现场就一句话返回值是正常的。第一次用户点了「禁止」代码走的是成功分支1.0.0 的授权流程用的是requestEnableNotification。我当时的理解是用户同意它就 resolve用户拒绝它就 reject。实际上用户点「禁止」它照样 resolve应用把这台设备当成已授权继续往下走。我以为是设备通知设置的问题让用户去把通知打开。开了还是不响。第二次通知开关关着publishReminder 返回了一个体面的 id还是 1.0.0。通知开关关闭时调publishReminder不抛异常返回一个正常的提醒 id——然后那条通知永远不会弹出来。我这回怀疑是提醒时间算错了去查时间计算。时间是对的。第三次我加了日志日志说成功到 1.2.1提醒改走日历事件。这回我学聪明了加日志打addEvent的返回值。返回了 id。界面上明明白白显示着「提醒 18:06」。但在一台从没打开过日历应用的设备上——审核那边的机器就是这样——日历应用未初始化事件写进了库里就躺在那儿提醒不会响。代码、日志、UI 三方合谋每一方都在说它在工作包括写它的人在内所有人都信了。三次之后我才看明白差在哪一步三次排查方向各不相同第一次怪设备设置第二次怪时间计算第三次去验写入结果。但它们共用同一个错误前提——把「调用方的返回值」当成了验收判据。这个前提在我自己的开发机上查不出来开发机的日历初始化过、通知授权过、权益齐备请求已受理和事情已发生在这台机器上几乎总是同时成立。同一份代码在这里是对的在那里是错的。这也是它能连踩三次的原因成功路径在开发机上是真的成功错误的前提在开发环境里永远不会暴露。修的时候我给判据排了个序宣称成功之前判据分三级权威回读 API 返回值 无异常。能回读就回读——事情做没做成去系统侧把结果读回来。有些外部状态压根没有查询接口回读不可达那时代码层正确的动作是向用户如实降级表述记一个lastViaFallback标记界面上说清楚这次走的是备用路径。不能验证的成功不许宣称。比防御代码更管用的是架构层的动作给这类功能配主路径之外的降级路径且几条路的失效前提要正交——权益状态、日历状态、进程存活各失效各的互不重叠才算冗余三条路都依赖同一个前提那就还是一条路。前两次事故我都加过防御代码第三次照样以新形态出现真正终结它的是把主路径换成了零外部依赖的那条。还有一条不许再犯发布失败不许静默。旧代码里publish失败返回 -1被 UI 吞掉外观就是设了提醒没反应。失败必须明示。怎么算修好坐在那儿等它响效果侧的验收就一种做法设一个提醒退到后台真的等它响。通知栏出现那条通知才算过。返回值不算界面显示「提醒 18:06」不算日志无异常也不算。想在自己工程里复现三分钟在系统设置里拒绝该应用的通知调requestEnableNotification打印返回的是 resolve 还是 reject再调publishReminder打印返回值。你会看到两个成功而通知不会来。边界别把这条读过头它不是说 API 返回值都不可信——绝大多数同步 API 的返回值就是结果本身。判别式就一句这个调用完成之后事情是不是还要靠别人做要靠系统侧接着兑现的提醒、通知、推送、卡片刷新返回值才仅仅是已受理。另外功能过简那类驳回和这条无关那是产品维度的事测试与判据都救不了。这是《鸿蒙开发踩坑实录》第 14 篇。后来我发现自己在别的事上也在拿「调用成功」冒充「事情发生」。本文由作者与 AI 协作整理事实经作者核验。