必须在app.vue的onlaunch中调用uni.getlaunchoptionssync()读取启动参数(如notification或plus.runtime.arguments),解析payload后等待uni.$on('app-ready')再跳转,避免依赖click事件;需兼容多厂商字段位置差异并做json解析与路径校验。

plus.push.addEventListener("click") 在离线场景下不触发怎么办
App被杀死后收到推送,用户点击通知时 JS 层根本没运行,plus.push.addEventListener("click", ...) 自然不会执行。这不是代码写错了,而是生命周期问题——原生进程启动后才拉起 JS 引擎,中间存在时间差。
必须在 App.vue 的 onLaunch 中主动读取启动参数,而不是依赖 click 事件监听:
-
uni.getLaunchOptionsSync()返回的对象里,notification字段(部分厂商如华为、小米会放在univerify或intent解析结果中)可能携带 payload - payload 必须是合法 JSON 字符串,例如:
{"page":"pages/order/detail","id":"123"},不能是纯字符串"pages/order/detail?id=123" - 拿到参数后不能立刻调用
uni.navigateTo,要等 Vue 实例就绪:uni.$on('app-ready', () => { /* 跳转 */ }),否则路由系统未初始化会静默失败
如何安全解析并跳转到 payload 指定的页面
payload 解析容易出错:字段缺失、格式非法、路径不存在、参数未编码都会导致跳转失败或白屏。
推荐用以下方式处理:
- 先做类型判断:
typeof msg.payload === 'string' ? JSON.parse(msg.payload) : msg.payload - 检查关键字段:
payload.page是否存在且为字符串,payload.page.startsWith('pages/')是否符合 uni-app 页面路径规范 - 拼接 URL 时统一加
/前缀:const url = '/' + payload.page + (payload.id ? '?id=' + encodeURIComponent(payload.id) : '') - 跳转前用
uni.preloadPage或uni.canIUse('preLoadPage')判断是否支持预加载(非必需,但可提升体验)
为什么 cid 获取为空导致跳转逻辑失效
有些业务需要在跳转前上报设备标识(如用于归因),但 plus.push.getClientInfoAsync 返回 cid: null 很常见。这不是 bug,而是 SDK 注册尚未完成。
错误做法是加 setTimeout 等几秒再取;正确链路是:
- 在注册推送服务后,立即监听
plus.push.addEventListener("register", callback) - 仅在该回调中调用
plus.push.getClientInfoAsync,此时cid才有可靠值 - 如果跳转逻辑依赖
cid(比如带参唤起 H5),建议把跳转延迟到注册完成后执行,或 fallback 到无 cid 的基础跳转
多厂商通道下 payload 字段位置不一致怎么兼容
华为、小米、OPPO 等厂商对透传消息的解析逻辑不同,有的塞进 notification.payload,有的走 intent.getStringExtra("payload"),还有的藏在 univerify 下。uni-app 不会自动归一化这些差异。
实际适配建议:
- 不要只读
uni.getLaunchOptionsSync().notification?.payload - 优先检查
plus.runtime.arguments(Android 启动 Intent 参数,含原始透传内容) - 对华为设备,额外解析
uni.getLaunchOptionsSync().univerify?.payload - 最终 fallback 到
plus.push.getClientInfoAsync后再查一次最近一条通知记录(需原生层支持存储)
最稳妥的方式,是在服务端推送时统一用标准字段名(如 page、id),并在原生插件层做一次标准化提取,JS 层只对接一个干净结构。











