UniPush 2.0 进阶实战:云函数+厂商通道,搞定APP离线推送全链路
1. 为什么你的UniPush离线推送总失败很多开发者跟我吐槽明明按照文档配好了UniPush测试时在线推送能收到但用户手机一锁屏推送就石沉大海。 这其实就是典型的离线推送失效问题。我去年接手的一个充电类APP就遇到过同样情况——用户充电完成后APP在后台时根本收不到推送通知差点被应用商店下架。离线推送的本质是当APP进程被杀死时由手机厂商的系统级推送服务来接管消息分发。但各厂商的推送通道就像不同国家的海关都有自己的特殊通关文牒要求。华为要报关单小米要通行证vivo要货物清单缺了任何一项都会被拦截。2. 厂商通道参数全解析2.1 华为通道(HW)的快递标签华为推送有个特别的设计——消息分类系统。就像快递要区分是普通包裹还是生鲜冷链华为要求每条推送必须声明消息类型。实测发现如果漏掉这个参数华为设备上离线推送成功率直接掉到30%以下。关键配置项HW: { /message/android/category: EXPRESS }可选值包括EXPRESS即时消息如订单状态变更VOICE语音类通知SOCIAL社交互动消息去年我们有个电商项目就栽在这里。当时所有华为手机用户都收不到订单发货通知排查三天才发现是没填category字段。补上这个参数后推送成功率立刻提升到98%。2.2 vivo通道(VV)的订单分类vivo的通道参数更像是在给消息打标签。他们的系统会根据/category字段对推送进行分级处理。如果不指定这个值vivo设备每天最多只能接收5条离线推送——这对大多数APP来说根本不够用。正确配置示例VV: { /category: ORDER }常见业务场景对应的分类ORDER交易订单类SOCIAL社交互动类SYSTEM系统通知类有个坑要注意vivo的文档里写着这个字段非必填但实际测试发现不填就会被限流。我们曾用10台vivo设备做压力测试不填category的设备在第6条推送时就全部失效了。2.3 小米通道(XM)的通行证小米的机制最特殊——要求开发者必须提前申请channel_id。这个过程就像办签证需要提交材料审核。很多开发者卡在这一步因为小米审核可能需要1-3个工作日。申请步骤登录小米开放平台进入推送运营→通道管理新建通道填写APP包名和用途说明等待审核通过代码中这样使用XM: { /extra.channel_id: MI_APPROVED_CHANNEL_ID }去年我们有个健身APP就吃过亏。上线前一天才发现小米推送没配置紧急申请通道又遇到周末最后不得不临时关闭小米设备的离线推送功能。建议大家在开发初期就先把各厂商通道申请好。2.4 OPPO通道的邮件申请OPPO的流程最复杂需要邮件申请私信通道。很多开发者在这里放弃治疗但其实只要按标准流程走2天内就能搞定。完整申请流程登录OPPO开放平台下载《OPPO推送通道申请表》填写APP信息和使用场景发送邮件至pushoppo.com收到包含Channel_ID的回复邮件配置示例OPPO: { /channel_id: OPPO_APPROVED_ID }特别提醒OPPO对推送内容审核最严格。我们有个新闻APP就因推送内容含敏感词被永久封禁通道后来重新注册企业账号才解决。3. 云函数推送模板大公开下面这个云函数模板集成了四大厂商的全部特殊参数已经在我们7个上线项目中验证过稳定性const uniPush require(unipush-sdk); exports.main async (event, context) { // 构造推送消息体 const pushPayload { cids: event.deviceTokens, title: event.title, content: event.content, data: event.customData, options: { VV: { /category: event.category || SYSTEM }, HW: { /message/android/category: EXPRESS }, XM: { /extra.channel_id: process.env.XIAOMI_CHANNEL_ID }, OPPO: { /channel_id: process.env.OPPO_CHANNEL_ID } }, request_id: Date.now().toString() }; try { const result await uniPush.send(pushPayload); return { success: true, data: result }; } catch (error) { console.error(推送失败:, error); return { success: false, error: error.message }; } };使用技巧将厂商通道ID放在环境变量中process.env避免硬编码request_id用时间戳生成确保每次推送都是唯一请求通过event参数动态传入设备token和推送内容这个模板最精髓的部分在于options字段的动态处理。我们通过event.category让调用方可以指定vivo的消息分类同时给其他厂商设置了合理的默认值。4. Postman测试全流程指南用Postman测试时90%的失败都是因为Body格式不对。这是我用坏三个回车键才总结出的正确姿势设置HeadersContent-Type: application/jsonAuthorization: Bearer your_api_key请求体示例{ cids: [测试设备token], title: 充电完成通知, content: 您的电动车已充电完成请及时拔除电源, data: { order_id: 123456, station_id: A12 }, options: { VV: { /category: ORDER }, HW: { /message/android/category: EXPRESS }, XM: { /extra.channel_id: 你的小米通道ID }, OPPO: { /channel_id: 你的OPPO通道ID } }, request_id: 1621234567890 }常见测试陷阱忘记加options字段表现为在线能收离线收不到cids写成字符串而非数组直接报参数错误重复使用request_id第二次请求会被视为重复推送厂商参数拼写错误比如华为的category写成categroy建议在测试阶段开启uniPush的详细日志我们就是通过日志发现某个华为设备的category值被错误覆盖的问题。5. 避坑指南血泪经验总结厂商限制策略华为未分类消息限流1000条/天vivo未分类消息每天最多5条/设备OPPO内容违规直接封禁通道小米未配置channel_id直接拒绝参数优先级陷阱 当title和content与厂商后台配置的模板冲突时部分厂商会优先使用模板内容。我们在vivo设备上就遇到过推送显示默认通知内容的问题后来在vivo开发者后台关闭模板匹配才解决。通道生效延迟 新申请的OPPO通道可能要2小时才能生效。有次我们半夜上线新功能测试失败后排查到凌晨才发现是OPPO缓存延迟。设备注册时机 部分华为设备需要用户手动开启允许自启动才能注册推送通道。我们的解决方案是在APP启动时检查通道状态如果未注册就弹窗引导用户设置。厂商文档过时 vivo的文档去年更新过三次参数格式最稳妥的方式是直接问他们的技术支持要最新版API文档。我们现在维护着一个各厂商最新参数的对照表每月都会检查更新。