好久没写公众号了。
最近一直在忙一款 App,名字叫「时光笺」。它主要做时间管理、待办、拾光记录和团队协作,里面也接了一个 AI 助手「小宇」,可以用比较口语化的方式快速记录待办,也会帮用户检测日程冲突。
因为有好友申请、待办分享、日程提醒、协作消息这些场景,消息推送就成了一个绕不开的能力。
一开始我以为这件事挺简单:接一个第三方推送平台,App 端拿到 token,后端集成 SDK,然后调用接口把消息发出去就行了。
刚开始联调的时候也确实没什么问题。几个测试同事打开 App,互相添加好友、分享待办,消息基本都能正常收到。
所以一开始大家都觉得,推送这块应该没什么大问题。
直到有一次测试过程中,手机自动熄屏了。
再发消息,收不到了。
第一反应:是不是后端推送失败了?
做后端开发的人,遇到这种问题第一反应通常都差不多:先看日志。
我当时也是这么想的。
是不是后端接口没调成功?是不是第三方平台返回失败?是不是 token 没绑定对?是不是用户和设备关系没维护好?
结果查了一圈,后端日志显示推送接口调用是成功的,第三方平台也正常返回了结果。
这就有点尴尬了。

从后端视角看,消息已经发出去了;但从用户视角看,手机就是没收到。
后来和第三方推送平台的技术人员沟通,才把这个问题捋清楚:App 打开的时候能收到,不代表 App 息屏、切后台、被系统回收之后还能收到。
这里已经不是普通在线推送的问题了,而是进入了离线推送场景。
在线推送和离线推送不是一回事

很多人第一次接 App 推送,容易把这两件事混在一起。
简单理解:
在线推送:App 还活着,连接还在,消息可以通过在线通道下发。 离线推送:App 切后台、息屏,甚至进程被系统回收,普通长连接不一定还能保持,这时就要走手机厂商的系统级推送通道。
在前台测试的时候,推送正常,并不能说明离线推送已经通了。
尤其是 Android 这边,各个厂商对后台进程、息屏省电、通知权限都有自己的策略。你不能假设 App 一直在后台老老实实等消息。
用户把手机放那儿不用,系统为了省电,会限制后台活动;App 的连接断了,消息自然就到不了。
这时候要想让用户还能收到通知,就需要接入华为、vivo、荣耀、小米、OPPO 这些厂商的离线通道。
这也是我这次踩坑的核心点:接了第三方推送平台,不等于离线推送天然可用。
第三方推送平台只是入口,厂商通道才是关键
第三方推送平台的价值是帮你统一封装各个厂商通道。
从开发体验上看,你不用分别对接华为、小米、OPPO、vivo、荣耀的服务端接口,也不用自己维护一堆差异化逻辑。
但这不代表你什么都不用管。
真正到了离线推送场景,底层还是要依赖厂商通道。你的消息最终能不能在息屏、切后台、杀进程后触达用户,取决于厂商通道有没有配置好、权限有没有申请、消息分类有没有传对。
有些平台还会把厂商离线通道放在高级能力里。也就是说,你只是接了基础推送,不代表离线通道一定生效。
这个点最好在项目早期就问清楚,不要等测试阶段才发现:在线没问题,一息屏就不行。

厂商通道麻烦在哪里?
麻烦不在于“能不能发一条消息”,而在于每个厂商都有自己的规则。
比如同样是消息推送,有的厂商叫服务与通讯,有的叫私信消息,有的叫系统消息,有的叫服务通讯。
这些名字看起来不一样,但背后的思路差不多:厂商会区分消息是不是和用户强相关。
像好友申请、待办分享、日程提醒、协作消息,这类一般属于服务类、通讯类、系统类消息。它们和用户当前使用 App 的业务直接相关,应该尽量及时触达。
但如果是活动推广、内容推荐、营销通知,就会被归到资讯营销、运营消息、公信消息这类低优先级通道里。
低优先级消息通常会有数量限制,有些还会在夜间静默、延迟,甚至直接丢弃。
所以这里不是随便填个参数就完事。
消息分类填错了,后果可能是:
原本应该及时到达的消息,被当成营销消息限量; 明明接口返回成功,但用户侧收不到; 夜间消息被静默、延迟,甚至不下发; 某个厂商正常,换个品牌手机就异常。
这类问题最麻烦的地方在于:从后端日志看,很多时候都是“成功”的。
但推送成功,不等于用户真的收到了。
五大厂商都要测,不能只拿一台手机验证
我们这次适配了华为、vivo、荣耀、小米、OPPO 这几个主流厂商。
做完之后最大的感受是:App 推送测试不能只拿一台手机。
你在某个品牌手机上测通了,只能说明这个品牌当前场景没问题,不代表其他厂商也没问题。
比较稳妥的测试方式,至少要覆盖这几种状态:
App 前台运行时,消息能不能收到; App 切到后台后,消息能不能收到; 手机息屏后,消息能不能收到; App 被杀掉后,消息能不能收到; 不同厂商手机上,消息表现是否一致; 通知权限关闭后,App 是否有合理提示; 用户点击通知后,能不能跳到正确业务页面。
尤其是息屏和杀进程这两个场景,最容易暴露问题。
因为它们才是真正接近用户日常使用状态的场景。
通知栏消息不要当成业务消息本体
这次排查推送问题时,还有一个点我觉得也值得单独说一下:通知栏推送和站内消息要分开设计。
通知栏消息只是提醒用户。
用户可能没看到,可能划掉了,也可能系统没展示。但业务消息本身不能因为通知没展示就丢了。
比如时光笺里有待办分享、好友申请、协作消息,这些都不能只依赖通知栏。
更合理的做法是:
服务端保存业务消息; App 打开后从服务端同步消息列表; 通知栏只负责提醒; 用户点击通知后,再进入对应页面; 是否已读,要由 App 根据用户行为上报。
这样即使某次推送没有触达,用户打开 App 后依然能看到对应消息。
推送是触达手段,不应该成为业务状态本身。
给准备接 App 推送的几个建议
这次问题解决之后,我自己也整理了几个经验。
第一,项目一开始就要区分在线推送和离线推送。
前台能收到,不代表息屏后也能收到。联调阶段最好直接把后台、息屏、杀进程这些场景都测掉。
第二,不要只看接口是否返回成功。
推送平台返回成功,只能说明平台接收了你的请求,不能直接等同于设备展示了通知。
第三,厂商通道能力要提前确认。
如果使用第三方推送平台,要问清楚厂商离线通道是否包含在当前套餐里,是否需要额外开通,是否需要单独配置各厂商应用信息。
第四,消息分类要认真设计。
好友申请、待办分享、日程提醒、协作消息,这类和用户强相关的消息,要按服务类、通讯类、系统类消息去申请和配置。营销类消息不要混用高优先级通道。
第五,测试机型要覆盖主流厂商。
华为、vivo、荣耀、小米、OPPO 最好都测一下。不要只在一台手机上验证通过,就认为推送能力没问题。
第六,重要业务消息一定要落库。
通知栏可以丢,业务消息不能丢。站内消息和服务端状态要作为最终依据。
最后
这篇文章算是时光笺开发过程中的一篇笔记。
以前写公众号,更多是单独讲某个技术点。现在自己从零做一款 App,反而发现很多问题只有真正做产品时才会遇到。
消息推送就是这样。
看起来只是“后端调个接口,手机弹个通知”,真做起来才发现,App 在线、离线、厂商通道、消息分类、通知权限、站内消息、点击跳转,每一层都可能出问题。
后面我也会继续用公众号记录时光笺从开发、上架、推广到迭代过程中遇到的问题。
如果你也在做 App,尤其是正在接消息推送,希望这篇踩坑记录能给你一点参考。
感兴趣的话,也可以去应用商店搜索「时光笺」体验一下。告别时间焦虑,就选时光笺。
我是南哥,10年全栈工程师,小公司项目经理
喜欢研究新技术,分享技术干货
回复“AI入门”,领取7本AI入门电子书;
回复“AI学习”,领取17本AI必看电子书;
夜雨聆风