Feature Branch: 033-native-push-routing
Created: 2026-09-29
Status: 服务端路由与随包 classpath 凭据已实现;默认 uni,原生通道未启用且真机投递未验证
Input: 为现有普通业务通知增加 Android FCM 与 iOS APNs 原生发送能力,以服务端配置切换,重启后生效;交付时继续默认使用 uniPush,不启用原生通道。仅涉及服务端;音视频通话推送不在范围内。
当前业务推送通过 PayPush 调用用户、商家、骑手三套 uniCloud 云函数,部分路径通过 PushEvent 写入 push_message。info_user 已有 cid、cidType、deviceToken:cid 是 uniPush 标识,deviceToken 承载 Android FCM token 或 iOS APNs device token,两者不可互用。用户已确认同一账号只允许一台手机登录,新手机登录后旧手机登录状态失效,因此本功能沿用现有单设备字段,不新增推送设备表。
本功能覆盖当前仍在使用的普通业务通知,包括订单、闪送、支付结果及平台/商家通知等现有发送路径;只替换发送通道,不增加新的业务触发时机或文案。不修改已废弃的支付/订单入口、临时测试推送接口,也不改动音视频通话推送。App 端 token 获取、上报及通知展示不在本功能实现范围;服务端以已有上报字段为输入。
运维部署新版本后,不做任何切换,普通业务通知仍按现有路径发送,不因原生凭据尚未部署而影响服务启动。
Why this priority: 先交付原生能力但暂不启用,必须保证当前线上推送行为不变。
Independent Test: 不设置通道配置,触发用户、商家、骑手各一条现有业务通知,验证只调用对应 uniCloud 通道。
Acceptance Scenarios:
uni,When 任一普通业务通知触发,Then 仅走现有 uniPush 通道,不调用 FCM/APNs。运维将普通业务推送配置切换为原生并重启服务后,Android 接收方通过对应 App 的 FCM 项目收到现有通知。
Why this priority: 这是 Android 原生通知的核心能力,同时必须避免误把 uniPush CID 当作 FCM token。
Independent Test: 在原生配置下,分别向用户、商家、骑手 Android 账号触发通知,验证使用各自 Firebase 项目和 deviceToken,且未调用 uniCloud。
Acceptance Scenarios:
native、接收方系统为 Android 且有有效 deviceToken,When 普通业务通知触发,Then 通过该接收端对应的 Firebase 项目向 deviceToken 发送一次;不得把 cid 传给 FCM。同一原生配置下,iOS 接收方通过对应 App 的 APNs 普通通知证书收到现有通知。
Why this priority: 只有 Android FCM 不满足“三端全切原生”的目标。
Independent Test: 在原生配置下,分别向用户、商家、骑手 iOS 账号触发通知,验证使用各自普通推送证书、正确环境与 deviceToken,且未调用 uniCloud。
Acceptance Scenarios:
native、接收方系统为 iOS 且有有效 deviceToken,When 普通业务通知触发,Then 通过该接收端对应的 APNs 普通通知证书向 deviceToken 发送一次;不得使用 voIPToken。运维能通过修改服务端配置并重启,在 uniPush 与原生通道间切换。单次通知只选择一个通道;发送失败不影响订单等业务操作。
Why this priority: 切换期间必须避免重复通知、业务流程被第三方推送故障阻断,以及随包凭据被写入日志或向非授权方分发。
Independent Test: 用缺失 token、原生服务异常、缺失凭据及配置回退场景验证发送结果、业务结果与消息中心记录。
Acceptance Scenarios:
native 且原生 token 缺失或发送失败,When 普通业务通知触发,Then 记录可定位的失败信息,不自动补发 uniPush,也不改变原业务操作结果。PushEvent 写入消息中心,When 任一通道发送成功、失败或 token 缺失,Then 保持原有入库语义,每次业务通知最多写入一条记录,不因切换重复入库。native 改回 uni 并重启,When 后续通知触发,Then 重新使用 cid 和 uniPush,不再调用 FCM/APNs。cidType 为空或不是 android/ios:原生模式下不猜测平台,不尝试使用错误通道;记录失败,保持业务和原有消息中心行为。deviceToken 为空、失效或来自另一 App/项目:不把 cid 当作替代 token;记录失败结果,失效 token 的后续处理应避免误删新手机刚更新的 token。cidType 与 deviceToken 为发送目标;本功能不改变现有登录互斥机制。deviceToken 判断可发送性,不得因 CID 为空漏掉有原生 token 的收件人。uni/native,未配置时默认为 uni;修改后重启生效,不新增管理后台实时开关。uni 模式 MUST 保持现有用户、商家、骑手 uniCloud 发送行为与消息中心入库行为;不得要求原生凭据存在。native 模式 MUST 根据接收端类型和 cidType 路由:Android 使用对应 App 的 FCM,iOS 使用对应 App 的 APNs;普通商家、夜市商家及商家子账号均属于商家端。deviceToken,uniPush MUST 只使用 cid;不得相互复制或替代,voIPToken 不得用于普通通知。packetName/pwd 配置 MUST 分别以 user、merchant、rider 明确命名并放在 ruoyi-admin/src/main/resources/business-push/,由 classpath 读取。用户已明确要求这些真实凭据提交 Git 并随 JAR 打包;不得把私钥或密码写入日志、规格正文或推送响应。仓库和构建产物必须按含密钥材料管理。ios.p12 与 iosdev.p12 经核对文件完全相同,资源中每端只保留一份 APNs 普通推送 .p12。development/production 只切换 APNs 网关,不切换证书文件;三端证书、Firebase 项目和 topic 不得混用。push_message 记录;消息中心记录与外部发送结果保持解耦。info_user 单设备字段,不新增数据库字段或设备表。native 模式对 Android 骑手按相同标题、正文及 payload 分组,使用骑手端 FCM multicast 发送;iOS 骑手保留逐设备 APNs 请求,uni 模式保留原有逐骑手发送方式,不接入旧批量方法。各骑手的语言、消息中心记录和发送失败处理 MUST 保持独立,原生失败不得回退 uniPush。cid、cidType、deviceToken;同一账号仅保留当前手机的一组推送标识。push_message,继续按原路径写入,不作为外部发送成功的证明。uni/native 配置,以及已提交资源目录的三端 FCM/APNs 凭据;不属于业务数据库数据。deviceToken,未把 cid 或 voIPToken 发送到原生通道。uni 并重启后,后续受测通知恢复原 uniPush 发送路径;音视频通话路径保持原行为。deviceToken 与正确的 cidType;App 端变更和真机展示不包含在此次服务端交付范围。uni 为默认值;凭据虽随包提供,只有运维确认 App 端 token、将服务端配置切为 native 并重启,才会启用原生通道。voIPToken 及 VoIP 证书不用于本功能。uni 下不加载这些凭据。