必须在app.vue的onlaunch中用plus.push.addeventlistener分别监听receive、click、online事件:receive处理通知到达(含厂商通道内容),click处理用户点击跳转(需判冷/热启动),online捕获前台透传消息;不可依赖uni.onpushmessage,因其在厂商通道下不稳定。

如何在 App.vue 中监听并区分 receive / click / online 事件
uni-app 的 plus.push.addEventListener 是分类处理推送消息的入口,但很多人只绑定了 receive,结果点击通知没反应、前台收不到透传、后台唤醒逻辑缺失。关键不是“有没有监听”,而是“监听什么、怎么分发”。
-
receive:设备收到通知(无论前台/后台),含离线厂商通道下发的内容;iOS APNs 消息会带aps字段,Android 厂商通道通常走payload或原始字段 -
click:用户点击通知栏条目触发,此时 App 可能被拉起或从后台切到前台,msg内容与receive基本一致,但需额外判断启动场景 - 不监听
online类型(如个推透传)会导致前台消息静默丢失——它不会触发receive,必须用plus.push.addEventListener("online", ...)单独捕获
示例片段(App.vue onLaunch 内):
plus.push.addEventListener("receive", (msg) => {
if (msg.aps) {
// iOS APNs 通知
handleIOSNotify(msg);
} else if (msg.payload && msg.payload.type === "order") {
// 华为/小米等厂商通道携带的业务字段
handleOrderNotify(msg.payload);
}
});
plus.push.addEventListener("click", (msg) => {
// 点击后跳转逻辑,注意区分是冷启动还是热启动
const isColdStart = !plus.runtime.isApplicationRunning();
navigateToOrderDetail(msg.payload?.orderId, isColdStart);
});
plus.push.addEventListener("online", (msg) => {
// 仅前台生效的透传消息,比如实时聊天新消息
handleOnlineMessage(msg);
});
为什么不能只靠 uni.onPushMessage 做分类
uni.onPushMessage 是 uni-app 封装层 API,但它在 Android 厂商通道下表现不稳定:华为、小米等离线推送到达时,该回调可能不触发;iOS 在冷启动后首次 onPushMessage 也可能拿不到完整 payload。这不是 bug,是底层 SDK 与 uni-app 生命周期桥接的固有限制。
-
uni.onPushMessage适合做简单通知展示,不适合承载业务路由或状态同步逻辑 - 真机调试时,
plus.push系列 API 才是唯一可靠入口,尤其涉及cid获取、权限检查、多通道 fallback - 如果你发现某些机型收得到通知但进不了
uni.onPushMessage,基本可以确定是厂商通道未走 uniPush 网关,或 manifest.json 中 push 配置漏项
如何根据消息类型动态决定是否弹窗、跳转或静默处理
分类处理的核心不是“收到就干啥”,而是“收到后结合当前状态判断该干啥”。比如订单类消息需要强提醒+跳转,系统公告可静默存本地,而聊天消息在前台应走内嵌弹窗、后台才走通知栏。
- 用
plus.runtime.isApplicationRunning()判断 App 是否在前台,避免重复弹窗 - 用
plus.push.getClientInfo()获取当前生效的推送通道(channel: "huawei"或"xiaomi"),不同通道字段结构差异大,不能硬解msg.content - 业务字段建议统一放在
payload下,且服务端推送时必须带上type字段,前端 switch 分支才可控 - Android 12+ 必须先请求
android.permission.POST_NOTIFICATIONS,否则plus.push.createMessage会静默失败,连日志都不报
cid 缓存失效导致分类逻辑错乱的典型表现
很多团队把 cid 存 localStorage 后就不管了,结果出现“同一台手机收不到推送”“点击通知跳转错误用户页面”等问题。根本原因是 cid 并非永久有效:厂商 SDK 可能因清理缓存、升级、重装 App 而重置,uniPush 后台也会定期轮换绑定关系。
-
cid必须在每次onLaunch和onShow时调用uni.getPushClientId()主动刷新,而不是只取缓存值 - 服务端绑定
cid时,要同时记录时间戳和通道类型,超过 7 天未活跃的 cid 应标记为待验证 - 前端收到消息后,若发现
cid与本地缓存不一致,应立即上报新值并清空旧业务状态(比如未读数、临时 token)
最常被忽略的是:cid 变更后,旧消息仍会推送到老 cid,但新 cid 已无法关联历史用户数据——这会导致分类后的跳转目标完全错位。











