# 厂商推送测试三件套(push 族) > 所属:push 组(前缀 `/api/v1/push`,源 `app/api/v1/push.py`) | 鉴权:**全部 Bearer** | [← 返回 API 索引](./README.md) > > 发送实现:`app/integrations/vendor_push.py`(荣耀 / **华为** / 小米 / OPPO / vivo 五通道, > `send_notification()` 通用入口)。站内消息中心见 [notifications.md](./notifications.md)。 > 与 `POST /api/v1/device/push-test`(无障碍召回通道延迟自测)互补:本组面向消息中心 13 类 push 的文案/参数/通道联调。 > > 字段命名同 notifications 族:**camelCase**。 ## 链路总览 ``` 真实业务事件(奖励过期/提现回执/审核通过/…) └→ vendor_push.send_notification(vendor, token, title, body, extras) extras = { type, notificationId, ...业务参数 } ← 客户端深链 + 已读联动的钥匙 客户端点击 push → 按 extras.type 直达落地页(与站内点击一致) → 调 POST /notifications/read {ids:[extras.notificationId]} 同步消红点(PRD §4) ``` 推送目标来源:客户端集成各厂商 push SDK 拿到 regId/token 后,通过 `POST /api/v1/device/register` 上报 `push_vendor` + `push_token`,服务端存 `device_liveness` 表。 ## GET /api/v1/push/vendors — 厂商配置状态 检查 5 家厂商服务端凭据是否配齐(只读 .env,不打厂商接口)。`missingKeys` 即还要补的配置键;mock 测试不依赖任何凭据。 ```jsonc { "vendors": [ { "vendor": "honor", "label": "荣耀", "configured": false, "missingKeys": ["HONOR_PUSH_APP_ID", "HONOR_PUSH_CLIENT_ID", "HONOR_PUSH_CLIENT_SECRET"] }, { "vendor": "huawei", "label": "华为", "configured": false, "missingKeys": ["HUAWEI_PUSH_APP_ID", "HUAWEI_PUSH_APP_SECRET"] }, { "vendor": "xiaomi", "label": "小米", "configured": true, "missingKeys": [] }, { "vendor": "oppo", "label": "OPPO", "configured": false, "missingKeys": ["OPPO_PUSH_APP_KEY", "OPPO_PUSH_MASTER_SECRET"] }, { "vendor": "vivo", "label": "vivo", "configured": false, "missingKeys": ["VIVO_PUSH_APP_ID", "VIVO_PUSH_APP_KEY", "VIVO_PUSH_APP_SECRET"] } ] } ``` ## GET /api/v1/push/templates — 13 类通知的 push 模板预览 PRD §5 的 13 条 push 文案(标题固定 ≤11 字不带变量;正文 `{var}` 为变量,示例值即 PRD 示例)。对文案、看变量名用。 ```jsonc { "templates": [ { "type": "withdraw_success", "category": "withdraw_assistant", "categoryLabel": "提现助手", "cardStyle": "withdraw", "pushTitle": "提现到账提醒", "pushBodySample": "¥0.50已存入您的微信钱包,点击查看到账详情", // 用示例值渲染后的效果 "pushBodyTemplate": "¥{amount}已存入您的微信钱包,点击查看到账详情", "variables": ["amount"], "sampleVars": { "amount": "0.50" } } // ... 共 13 条,顺序即 PRD 编号 ] } ``` ## POST /api/v1/push/test — 测试发送(默认 mock) **入参(JSON)** | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `vendor` | string | ❌* | `honor/huawei/xiaomi/oppo/vivo`,中文「华为」「小米」等别名也识别;留空时用 `deviceId` 设备上报的 vendor | | `pushToken` | string | ❌* | 厂商 push token/regId;留空则按 `deviceId` 反查已注册设备(*mock 模式两者都缺时用占位 token,只看渲染结果*) | | `deviceId` | string | ❌ | 客户端 `DeviceId.get()` 的设备 id,用于反查 vendor+token | | `type` | string | ❌ | 13 种类型 key 之一 → 按 PRD 模板渲染;不传且没直给文案 → 发通用测试文案 | | `vars` | object | ❌ | 覆盖模板变量,如 `{"coins":"520","cash":"6.66"}`;缺省用 PRD 示例值 | | `title` / `content` | string | ❌ | 直接指定标题/正文(优先于 type 模板) | | `createNotification` | bool | ❌ | true = 同时往该用户消息中心插一条同类型未读 mock 通知,extras 带其 `notificationId` → 可闭环验证「点 push → 调 /notifications/read 消红点」(仅 type 合法时生效) | | `mock` | bool | ❌ | **默认 true = 不真调厂商 API**,回显渲染结果;false = 真发到手机(要求该厂商凭据已配) | **出参** ```jsonc { "ok": true, "mock": true, "vendor": "huawei", "title": "反馈奖励已到账", "body": "谢谢您帮傻瓜比价变得更好,300金币已到账,还有一条给您的留言~", "extras": { "type": "feedback_reward", "feedbackId": "3002", "notificationId": "90017" }, "notificationId": 90017, // createNotification=true 时的站内 mock 通知 id "missingKeys": ["HUAWEI_PUSH_APP_ID", "HUAWEI_PUSH_APP_SECRET"], // 真发前还缺的配置(真发成功时必为空) "vendorResponse": null // 真发时为厂商 API 原始响应 } ``` **错误**:`400` vendor/type 非法、真发但凭据未配(detail 列缺失键);`409` 真发但拿不到 pushToken;`502` 厂商 API 返回失败(detail 带厂商原始错误)。 **真发注意**: - 目标手机必须先装 App 且客户端已集成对应厂商 SDK、`/device/register` 上报过 token; - vivo 未上架前走测试推送(`VIVO_PUSH_MODE=1`),目标手机需在 vivo 开放平台加入测试设备; - 小米新设备需在开放平台把签名/包名配好,token 才有效。 ## 厂商凭据怎么拿(.env 键名) | 厂商 | 后台 | 需要的键 | |---|---|---| | 华为 | AGC 控制台 → 项目设置 → 常规 → 应用 | `HUAWEI_PUSH_APP_ID`、`HUAWEI_PUSH_APP_SECRET`(OAuth client_id 即 AppId) | | 荣耀 | 荣耀开发者服务平台 → 推送服务 | `HONOR_PUSH_APP_ID`、`HONOR_PUSH_CLIENT_ID`、`HONOR_PUSH_CLIENT_SECRET` | | 小米 | 开放平台 → 消息推送 → 应用秘钥 | `XIAOMI_PUSH_APP_SECRET`(服务端只要这个;AppID/AppKey 是客户端 SDK 用) | | OPPO | 开放平台 → 推送服务 | `OPPO_PUSH_APP_KEY`、`OPPO_PUSH_MASTER_SECRET`(注意是**服务端 MasterSecret**) | | vivo | 开放平台 → 推送 | `VIVO_PUSH_APP_ID`、`VIVO_PUSH_APP_KEY`、`VIVO_PUSH_APP_SECRET` | 各家发送协议差异(鉴权方式/成功码/payload 结构)封装在 `integrations/vendor_push.py`,业务侧只面对 `send_notification()`。