
uni-push 2.0 厂商推送配置与当前项目云函数说明目录1. 推荐接入总流程1.1 开通 uni-push 2.01.2 配置厂商推送通道1.3 开通并关联 uniCloud1.4 编写推送云函数1.5 获取当前设备 cid1.6 存储 cid 并和用户信息绑定1.7 每次登录都更新一次 cid1.8 云函数 URL 化1.9 推送成功后的点击解析2. push 云函数支持的请求参数2.1 目标参数2.2 消息主体参数2.3 通知行为参数2.4 HTTP 调用兼容说明3. 当前代码中的厂商参数映射3.1 Android 厂商参数3.2 HarmonyOS 参数3.3 category.harmony 的特殊处理4. 厂商配置要点4.1 华为4.2 荣耀4.3 小米4.4 OPPO4.5 vivo4.6 魅族4.7 HarmonyOS NEXT5. device_tokens 和用户绑定链路的区别5.1 device_tokens5.2 UpdAppChannelInfo5.3 结论6. 推荐请求示例6.1 当前项目后端实际调用示例6.2 与客户端点击跳转规则的对应关系6.3 全量推送说明7. 常见误区与注意事项7.1 只保存 device_id 不等于已经完成用户绑定7.2 厂商后台配好了不云打包也不会生效7.3 force_notification: true 会改变客户端接收体验7.4 request_id 建议每次唯一7.5 当前项目还没有覆盖所有厂商扩展字段7.6 push_logs 会记录完整请求体7.7 当前 appId 是写死的8. 排查建议9. 当前项目的推送链路9.1 push 云函数9.2 saveDeviceToken 云函数9.3 客户端登录后的用户绑定链路9.4 App.uvue 中的通知点击与角标处理9.5 通知点击处理9.6 角标清理逻辑本文结合以下内容整理- 官方文档https://uniapp.dcloud.net.cn/unipush_vendor_config.html- 官方文章https://ask.dcloud.net.cn/article/40283- 当前项目云函数uniCloud-alipay/cloudfunctions/push/index.js- 当前项目云函数uniCloud-alipay/cloudfunctions/saveDeviceToken/index.js目标是说明当前项目的推送链路、uni-push 2.0 的厂商配置要点以及现有代码和官方配置之间的对应关系。1. 推荐接入总流程结合官方文档、当前项目实现和你的实际接入要求推荐按下面这条顺序落地1. 开通 uni-push 2.02. 配置各厂商推送通道3. 开通并关联 uniCloud 服务空间4. 编写推送相关云函数5. 云打包并确认客户端可以获取当前设备 cid6. 把 cid 存储到 uniCloud 或业务后端并与当前用户信息绑定7. 每次登录成功后都更新一次当前 cid8. 将推送云函数做 URL 化供后端接口或外部服务调用9. 推送成功后在客户端完成点击通知解析和页面跳转每一步的目的如下1.1 开通 uni-push 2.0这是整个推送能力的起点。不先开通后面的客户端获取 cid、服务端发推、厂商离线通道都无从谈起。开通地址- https://dev.dcloud.net.cn/pages/app/push2/info1.2 配置厂商推送通道这一步不能只理解成“在 DCloud 开发者中心填参数”。完整流程通常是两段1. 先去对应厂商开放平台创建应用、开通推送能力、申请消息分类或通知渠道2. 再回到 DCloud 开发者中心填写对应厂商参数也就是说厂商通道配置完成前通常还需要先在对应平台完成申请和审核。具体以官方文档为准- https://uniapp.dcloud.net.cn/unipush_vendor_config.html开发者中心厂商推送通道设置入口- https://dev.dcloud.net.cn/pages/app/push2/thirdparty常见包括- 华为创建应用、开通推送服务、配置 SHA256、下载 agconnect-services.json- 荣耀创建应用、申请推送服务、获取 App ID / Client ID / Client Secret- 小米创建应用、获取 AppID / AppKey / AppSecret并根据消息分类要求申请渠道- OPPO创建应用、申请推送服务或消息分类、准备分类参数- vivo创建应用、申请推送能力、配置回执和分类- iOS制作并配置苹果推送证书单独说明见 uniCloud-alipay/uni-push-2.0-ios-p8-guide.md- 鸿蒙根据 HarmonyOS NEXT 要求配置消息分类和相关推送参数除了平台侧参数还要注意 Android 端本地资源配置- nativeResources/android/res- 这个目录可用于放置部分手机通知使用的小图标 logo- 如果通知小图标需要定制通常就在这个目录下按 Android 资源规范提供对应图片资源注意- 如果没有完成离线厂商推送配置通常只能在 App 在线时收到消息- 厂商平台侧的通道、分类、渠道 ID、模板、审核状态如果没准备好即使 DCloud 后台已经填了参数离线推送也可能仍然不可用- 厂商配置完成后必须重新云打包App 端才会生效1.3 开通并关联 uniCloud推送服务端一般需要依赖 uniCloud- 保存设备信息- 保存用户与 cid 的绑定关系- 编写云函数调用 uniPush.sendMessage- 后续把云函数 URL 化给业务后端使用1.4 编写推送云函数当前项目里已经有两个相关云函数- uniCloud-alipay/cloudfunctions/push/index.js- uniCloud-alipay/cloudfunctions/saveDeviceToken/index.js其中- push 负责发消息- saveDeviceToken 负责登记设备基础信息1.5 获取当前设备 cid客户端必须先能拿到当前安装实例对应的 cid后续服务端推送才有目标。当前项目里这一步由 utils/push.uts 完成。拿到 cid 后建议到开发者中心做一次离线推送能力核验- 地址https://dev.dcloud.net.cn/pages/app/push2/index- 路径配置管理 - 故障排查 - 状态查询- 输入当前设备 cid 后可以查询对应的 Device Token 是否存在结论- 能查到 Device Token说明该设备已经具备厂商离线推送基础条件- 查不到 Device Token通常说明当前还不具备离线推送能力此时消息大概率只能在 App 在线时送达1.6 存储 cid 并和用户信息绑定这一步是实际项目里最关键的一步。你当前项目里至少有两类绑定或登记方式- 调用 saveDeviceToken把设备信息写入 uniCloud- 调用 user/UpdAppChannelInfo把 cid 作为 channelNo 上传并和当前登录用户做业务绑定绑定关系最终可以保存在- uniCloud 表- 你们自己的业务表1.7 每次登录都更新一次 cid这一步必须单独强调。原因不是因为代码习惯而是因为 cid 本身不是永久不变- 你当前给出的业务规则是大约 90 天不使用cid 会失效一次- App 卸载后重新安装cid 会被重置所以推荐做法是- 每次登录成功后重新调用一次绑定接口- 用最新 cid 覆盖旧绑定关系当前项目的 pages1/login/login.uvue 已经在登录成功后调用 updateAppChannelInfo()这符合这个要求。1.8 云函数 URL 化如果推送请求不是只在 uniCloud.callFunction 内部调用而是需要给传统后端或外部服务使用就要把推送云函数 URL 化。这样后端接口才能通过 HTTP 方式调用推送能力。1.9 推送成功后的点击解析推送发出去只是前半段客户端点击通知后的解析同样重要。当前项目里这部分逻辑在 App.uvue 中完成- 监听 uni.onPushMessage- 只处理 click 事件- 解析 payload.url- 解析 payload.isHomePage- 执行 switchTab 或 navigateTo- 同时清空角标根据官方文章说明- uni-app x 标准基座默认不包含 uni-push 模块开发调试时通常需要先写入相关 API再制作自定义调试基座2. push 云函数支持的请求参数2.1 目标参数push 云函数要求至少传一个目标参数- cids- 可以是逗号分隔字符串- 也可以是字符串数组- 会直接作为 push_clientid 推送- 当前项目代码已限制 cids 最多支持 200 个- 当前项目代码已支持 cids 为空时表示全量推送优先级说明- 当前项目实际对接只使用 cids- 如果 cids 为空当前代码会走全量推送2.2 消息主体参数- title通知标题默认 新消息- content通知内容默认空字符串- payload自定义业务数据默认空对象- request_id请求唯一标识建议每次请求都传唯一值避免重复请求导致消息丢失2.3 通知行为参数- force_notification- 默认是 true- 设为 true 时客户端会自动创建通知栏消息- 结合官方文章说明这种模式下在线消息不会再走普通 receive 监听流程而更偏向通知栏展示和点击回调- settings- 透传给推送服务- 常见用法是设置 ttl当前项目使用系统默认声音不单独配置声音参数。2.4 HTTP 调用兼容说明当前 push 云函数兼容 HTTP 触发器但有两个前提- event.body 不能为空- event.body 必须是合法 JSON 字符串或者已经是对象否则会报以下错误之一- 请求体为空- 请求体格式无效3. 当前代码中的厂商参数映射当前项目并不是把 options 原样透传而是把调用方传入的扁平字段重新拼装成 uni-push 所需结构。3.1 Android 厂商参数当前 push 云函数支持以下映射| 传入字段 | 最终映射 | 说明 || --- | --- | --- || HW | options.android.HW[/message/android/category] | 华为 Android 消息分类 || HW_CHANNEL_ID | options.android.HW[/message/android/notification/channel_id] | 华为通知渠道 ID || HW_IMPORTANCE | options.android.HW[/message/android/notification/importance] | 华为重要级别 || HO | options.android.HO[/android/notification/importance] | 荣耀消息等级 || XM | options.android.XM[/extra.channel_id] | 小米渠道 ID || OP_CATEGORY | options.android.OP[/category] | OPPO 消息分类 || OP_NOTIFY_LEVEL | options.android.OP[/notify_level] | OPPO 提醒级别 || VV | options.android.VV[/category] | vivo 消息分类 || VV_NOTIFY_TYPE | options.android.VV[/notifyType] | vivo 通知类型 |3.2 HarmonyOS 参数当前 push 云函数支持以下映射| 传入字段 | 最终映射 | 说明 || --- | --- | --- || HM_TEST | options.harmony.HW[/pushOptions/testMessage] | HarmonyOS NEXT 测试消息 |3.3 category.harmony 的特殊处理当前代码对 Harmony 消息分类做了两层兼容1. 如果显式传了 category.harmony优先使用它2. 如果没有传 category.harmony则尝试从 options.HM 回退生成也就是说调用方可以直接这样传json{category: {harmony: MARKETING}}也可以兼容现有封装方式通过 options.HM 生成对应分类。4. 厂商配置要点官方配置文档- https://uniapp.dcloud.net.cn/unipush_vendor_config.html以下内容是根据官方厂商配置文档提炼出来并和当前项目代码的支持范围做对照后的结果。4.1 华为开发者后台需要完成- 创建应用- 开通推送服务- 配置 SHA256 证书指纹- 下载并保存 agconnect-services.json- 配置回执地址华为回执地址texthttps://thirdrcp-hz.getui.com/hw当前项目与华为相关的代码支持- HW消息分类- HW_CHANNEL_ID通知渠道 ID- HW_IMPORTANCE通知重要级别4.2 荣耀开发者后台需要完成- 创建应用- 填写包名和 SHA256 指纹- 获取 App ID、Client ID、Client Secret- 配置回执地址荣耀回执地址texthttps://thirdrcp-hz.getui.com/ho当前项目与荣耀相关的代码支持- HO映射到荣耀通知重要级别4.3 小米开发者后台需要完成- 创建应用- 获取 AppID、AppKey、AppSecret当前项目与小米相关的代码支持- XM映射为 /extra.channel_id重点提醒- 官方文章明确提到小米新消息分类下很多场景必须传 channel_id- 如果不传小米厂商通道可能直接拦截导致离线推送失败4.4 OPPO开发者后台需要完成- 创建应用- 获取 App ID、App Key、App Secret、Master Secret当前项目与 OPPO 相关的代码支持- OP_CATEGORY消息分类- OP_NOTIFY_LEVEL提醒等级重点提醒- 官方说明中提到OPPO 正式环境通常要求上架应用商店后才能正常使用厂商离线推送- 如果启用了新的消息分类分类值、模板、审核状态都要和 OPPO 平台配置一致否则容易出现“接口看似成功但收不到离线消息”的情况4.5 vivo开发者后台需要完成- 创建应用- 获取 AppID、AppKey、AppSecret- 配置 APP 回执地址- 如果使用回执能力还要记录回执 IDvivo 回执地址texthttps://receipt-hz.lmmindex.com/vv当前项目与 vivo 相关的代码支持- VV映射为 vivo 分类- VV_NOTIFY_TYPE映射为通知类型重点提醒- 官方文档里提到vivo 如果要统计回执推送时需要带回执 ID- 当前项目的 push 云函数尚未对 vivo 回执 ID 做专门映射如果后续需要完整的回执统计需要继续扩展 options 映射4.6 魅族官方厂商文档中包含魅族配置- 需要获取 AppID、AppKey、AppSecret- 回执地址如下texthttps://thirdrcp-hz.getui.com/mz但要注意- 当前项目的 push 云函数没有对 MZ 参数做显式映射- 也没有魅族专属消息分类字段封装这意味着- 官方后台配置可以做- 但如果你希望在当前项目里传魅族专属分类或扩展参数还需要继续改造 push/index.js4.7 HarmonyOS NEXT官方文章和 uni-push 文档都强调- HarmonyOS NEXT 的消息分类要通过 category.harmony 传递- 分类取值需要符合华为鸿蒙云端通知分类要求当前项目对 Harmony 的支持包括- category.harmony- HM_TEST5. device_tokens 和用户绑定链路的区别这是当前项目最容易混淆的地方。当前项目主要有两类相关数据链路- device_tokens设备登记- UpdAppChannelInfo业务后端的用户与 CID 绑定5.1 device_tokens由 saveDeviceToken 写入当前保存字段包括- device_id- brand- platform- osVersion- create_time它更像是一个自定义设备登记表。5.2 UpdAppChannelInfo这是当前项目业务后端的绑定接口- 接口名user/UpdAppChannelInfo- 客户端入参channelNo cid- 调用时机登录成功后这条链路的意义是- 把当前设备的 cid 和当前登录用户绑定起来- 绑定关系保存在哪里取决于你们自己的业务后端实现- 它不等于 saveDeviceToken5.3 结论- saveDeviceToken 负责设备登记- UpdAppChannelInfo 负责把当前设备 cid 和当前登录用户绑定- 当前项目的业务推送由后端触发云函数负责实际推送6. 推荐请求示例6.1 当前项目后端实际调用示例下面这份参数更接近当前项目后端真实调用方式同时也符合 App.uvue 的点击跳转逻辑jsonc{cids: 6ec428efe3e03274e5d6b1ec6debea41,title: 报告出来了,content: 速速查看身体状况维护身体健康。,payload: {url: /pages/report/report,isHomePage: true},options: {HW: HEALTH,HM: HEALTH,HO: NORMAL,XM: 152873,OP: TODO,VV: TODO},force_notification: true}说明- cids 是目标设备 CID最多支持 200 个传空表示全量推送- payload.url 和 payload.isHomePage 直接决定点击通知后的跳转行为- HW / HM / HO / XM / VV 都是当前项目实际在传的通道字段- OP 也是你们当前后端实际传参字段但按新版 OPPO 平台规则文档里的平台配置说明仍建议优先关注 OP_CATEGORY / OP_NOTIFY_LEVEL- request_id 建议正式环境始终传唯一值6.2 与客户端点击跳转规则的对应关系上面的示例之所以能和当前客户端配合是因为 App.uvue 点击通知时按下面的规则处理- 先从 res.data.payload 里取数据- 再读取 payload.url 作为跳转地址- 再读取 payload.isHomePage 判断是否跳 tabbar 页面所以如果后端希望点击通知后自动跳转推荐至少保持下面这个 payload 结构json{payload: {url: /pages/report/report?id1name张三,isHomePage: true}}注意- 如果是普通页面isHomePage 应传 false- 如果没有传 url当前客户端点击通知后只会清角标不会跳转页面- 如果要带参数直接拼在 url 后面即可6.3 全量推送说明按你们当前后端接口约定- cids 传具体值表示定向推送- cids 传空表示全量推送- cids 传空只表示推送范围是“全量”不代表可以省略厂商通道或消息分类参数示例json{cids: ,title: 系统公告,content: 全体用户请查看最新通知,payload: {url: /pages/index/index,isHomePage: true},options: {HW: ACTIVITY,HM: ACTIVITY,HO: NORMAL,XM: 活动通道号,OP: CONTENT,VV: CONTENT},force_notification: true}其中- XM 的活动通道号需要在小米平台单独申请注意- 全量推送属于高影响操作正式环境建议增加额外权限控制和审核- 全量推送通常仍要根据消息类型传对应厂商通道/分类参数- 如果是活动、营销类消息很多场景下需要走活动通道号或活动分类- cids 为空只代表目标范围不代表可以省略 options 或 category7. 常见误区与注意事项7.1 只保存 device_id 不等于已经完成用户绑定saveDeviceToken 负责设备登记不直接等于用户绑定。当前项目更直接的用户绑定入口是 updateAppChannelInfo()它会把当前 cid 作为 channelNo 上传给后端。7.2 厂商后台配好了不云打包也不会生效这是官方文章里反复强调的点。厂商参数配置完成后必须重新云打包App 端才能真正使用新的离线推送能力。7.3 force_notification: true 会改变客户端接收体验如果你希望在线时也走自己的 receive 监听逻辑并手动决定是否创建本地通知就不要默认把所有场景都交给 force_notification: true。7.4 request_id 建议每次唯一官方文章明确提到请求唯一标识如果重复可能导致消息丢失。当前项目代码只是透传并没有帮你生成唯一值所以调用方要自己保证唯一性。7.5 当前项目还没有覆盖所有厂商扩展字段当前项目文档只保留了现阶段业务实际用到的推送能力说明没有展开未接入的厂商扩展能力。7.6 push_logs 会记录完整请求体当前 push 云函数会把 requestBody 写入 push_logs。如果后续把敏感字段放进 payload 或请求参数需要额外评估日志脱敏和数据合规问题。7.7 当前 appId 是写死的uniCloud-alipay/cloudfunctions/push/index.js 里当前使用的是固定值jsappId: __UNI__*******这意味着- 如果当前服务空间只服务这一套 App并且 AppID 正确这样可以工作- 如果后续更换应用、拆分多环境、复用云函数到别的项目必须同步检查这里的 appId否则会出现- cid 属于当前安装包但服务端推送仍然发往旧应用- 调用看起来成功但目标设备实际收不到消息8. 排查建议- 定向推送收不到先查后端保存的 cid/channelNo 是否是当前最新值- 点击通知不跳转先查 payload.url、payload.isHomePage 是否传对- 收不到离线推送先查厂商平台配置、开发者中心参数和云打包是否已更新- 收不到离线推送时还要到 https://dev.dcloud.net.cn/pages/app/push2/index 的 配置管理 - 故障排查 - 状态查询 中输入 cid确认是否已经生成 Device Token9. 当前项目的推送链路当前项目里和推送直接相关的云函数有两个另外还有一条客户端登录后的业务绑定链路9.1 push 云函数文件uniCloud-alipay/cloudfunctions/push/index.js职责- 统一推送入口兼容 HTTP 触发器和 uniCloud.callFunction- 解析请求体并构造 uniPush.sendMessage 参数- 当前项目实际主要通过 cids 做定向推送或在 cids 为空时做全量推送- 支持 options、category、settings、force_notification 等扩展参数- 将推送成功或失败结果写入 push_logs9.2 saveDeviceToken 云函数文件uniCloud-alipay/cloudfunctions/saveDeviceToken/index.js职责- 接收客户端上传的 device_id、brand、platform、osVersion- 按 device_id 去重后写入 device_tokens注意这个函数保存的是设备基础信息不直接等于推送目标。9.3 客户端登录后的用户绑定链路文件utils/push.uts当前项目客户端实际上做了两件不同的事- bindPushDevice()- 获取 cid- 调用云函数 saveDeviceToken- 把 device_id、品牌、平台、系统版本写入 device_tokens- updateAppChannelInfo()- 获取 cid- 把 cid 作为 channelNo 提交到业务接口 user/UpdAppChannelInfo- 这条链路用于把当前设备的推送标识和当前登录用户做业务绑定- 这一步应当在每次登录成功后都执行一次不能只绑定一次后长期不更新从代码上看- utils/push.uts:181 会把 channelNo deviceId- utils/apiAddress.uts:9 把 UpdAppChannelInfo 映射到 user/UpdAppChannelInfo- pages1/login/login.uvue:426 和 pages1/login/login.uvue:469 会在登录成功后调用 updateAppChannelInfo()这里的用户绑定走业务后端接口。cid 也不是永久固定值按你当前业务规则大约 90 天不使用会失效一次卸载重装也会重置所以登录成功后应重新上报并更新。9.4 App.uvue 中的通知点击与角标处理文件App.uvue当前项目在应用入口还做了两类运行时处理- 注册通知点击监听- 在启动和回到前台时清空应用角标9.5 通知点击处理App.uvue:221 通过 uni.onPushMessage 监听推送消息但当前只处理 res.type click 的场景- 不是点击事件时直接返回- 点击通知后立即执行 uni.setAppBadgeNumber(0) 清空角标- 尝试从 res.data 中解析消息体- 优先读取 payload如果没有可用 payload则直接把 messageData 当成业务数据- 从消息数据中提取 url- 读取 isHomePage 决定是 switchTab 还是 navigateTo- 如果普通跳转失败会降级为 reLaunch点击通知要能跳转消息体里至少要有 payload.url 或顶层 url如果没有 url当前客户端只会清角标不会跳转。9.6 角标清理逻辑App.uvue 里目前有一处清角标方法定义以及三处实际触发点- App.uvue:44 定义了 clearAppBadgeOnEnter()内部调用 uni.setAppBadgeNumber(0)- App.uvue:349 的 onLaunch() 中会调用 clearAppBadgeOnEnter()- App.uvue:376 的 onAppShow() 中也会再次调用 clearAppBadgeOnEnter()- App.uvue:226 在用户点击通知时也会立即执行一次 uni.setAppBadgeNumber(0)这意味着当前项目的角标处理策略是- App 冷启动时清零- App 回到前台时清零- 用户点击通知时也清零如果后续业务希望保留未读数角标就需要重新设计这里的角标更新策略避免在进入前台时被无条件清空。