Files
im_server/docs/third/IM-极光推送完整调用流程.md
T

369 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# IM 极光推送完整调用流程
更新时间:2026-09-04
## 1. 流程目标
本文用于说明 IM 系统接入极光 JPush 后,离线消息、离线来电、系统通知和业务红点提醒从客户端注册设备、后端保存设备、服务端生成 Push 任务、调用极光 REST API 到客户端点击补偿拉取的完整链路。
官方参考:
- 极光快速开始:https://docs.jiguang.cn/jpush/quickstart/
- 极光 REST API 概述:https://docs.jiguang.cn/jpush/server/push/server_overview
- 极光创建推送 API:https://docs.jiguang.cn/jpush/server/push/rest_api_v3_push
## 2. 整体链路
```text
后台配置极光参数
-> 客户端集成 JPush SDK
-> 客户端获得 registration_id
-> 客户端登录 IM 后上报设备 Push Token
-> IM Server 保存 user_id/device_id/provider/registration_id/platform
-> 用户离线或目标设备不在线
-> IM Server 生成离线 Push 任务
-> Push worker 调用极光 POST /v3/push
-> 极光下发通知到 Android/iOS/HarmonyOS
-> 用户点击通知打开 App
-> 客户端按 extras 中的 topic/seq/call_id 跳转并补偿拉取
```
## 3. 后台配置流程
配置建议存放在 HotGo 后台 `hg_sys_config`,分组建议使用 `im_jpush`。IM Server 通过 Admin 内部配置接口读取并缓存,配置变更后通过 Kafka 配置事件或进程内缓存过期生效。
| 配置项 | 示例 | 说明 |
| --- | --- | --- |
| `jpush_enabled` | `true` | 是否启用极光推送。 |
| `jpush_app_key` | `xxxxxxxx` | 极光应用 AppKey。客户端 SDK 初始化也会用到,允许给客户端配置使用。 |
| `jpush_master_secret` | `******` | 极光 REST API 密钥,只能后端保存和使用,不允许返回客户端。 |
| `jpush_api_domain` | `https://api.jpush.cn` | 极光 REST API 域名。 |
| `jpush_push_path` | `/v3/push` | 创建推送 API 路径。 |
| `jpush_apns_production` | `false/true` | iOS APNs 环境,测试包用 false,生产包用 true。 |
| `jpush_default_ttl_seconds` | `86400` | 离线 Push 默认保留时长。 |
| `jpush_call_ttl_seconds` | `60` | 来电 Push 保留时长,建议短一些。 |
| `jpush_use_alias` | `true` | 是否优先使用极光安全 alias 投递。 |
| `jpush_test_model` | `false` | 极光测试模式,仅联调测试设备时开启。 |
| `jpush_classification` | `1` | 重要业务通知建议按系统消息分类处理,需结合厂商通道规则确认。 |
| `jpush_log_payload` | `false` | 生产关闭 payload 明文日志,避免敏感信息进入日志。 |
## 4. 客户端初始化流程
### 4.1 获取极光配置
客户端安装包通常内置对应环境的 `AppKey`,也可以从 App 配置接口获取非敏感配置。`MasterSecret` 不允许下发。
客户端需要完成:
1. 集成 JPush SDK。
2. 初始化 SDK 使用 `jpush_app_key`。
3. 申请系统通知权限。
4. 取得 `registration_id`。
5. 登录 IM 后绑定 alias。极光 alias 不支持中横线 `-` 和下划线 `_`,客户端必须将当前 IM `user_id` 转成极光安全别名:`user_id.replace("-", ".").replace("_", "|")`。示例:`usrd6Ag5opa-ww` 对应 `usrd6Ag5opa.ww`。
6. 调用 IM 后端设备接口上报 Push Token。
### 4.2 设备上报
```http
PUT /v1/im/devices/{device_id}/push-token
Authorization: Bearer <IM token>
X-MeetingIM-APIKey: <api_key>
X-IM-Schema: 1
X-Tenant-Code: <tenant_code>
X-Request-ID: <request_id>
Idempotency-Key: <idempotency_key>
Content-Type: application/json
```
请求 Body:
```json
{
"provider": "jpush",
"token": "registration_id_from_jpush",
"platform": "android",
"app_version": "1.0.0",
"push_env": "test",
"sdk_version": "5.0.0",
"notification_permission": "granted"
}
```
成功响应:
```json
{
"code": 0,
"data": {
"device_id": "device_1",
"provider": "jpush",
"platform": "android",
"app_version": "1.0.0",
"updated_at": "2026-09-04T10:00:00Z"
},
"request_id": "req_01K...",
"server_time": "2026-09-04T10:00:00Z"
}
```
### 4.3 设备解绑
退出登录、删除设备、切换账号或 SDK 返回 registration_id 失效时,客户端应调用设备解绑接口或覆盖上报为空状态。后端要把该设备 token 标记为 disabled,避免继续推送到错误账号。
## 5. 服务端 Push 任务生成
### 5.1 触发场景
| 场景 | 触发条件 | Push 目标 |
| --- | --- | --- |
| P2P 离线消息 | 接收方当前无在线可投递设备,或需要离线提醒 | 接收方 user_id。 |
| 群离线消息 | 成员离线且未免打扰,按 Topic seq 补偿 | 被提醒成员 user_id,不对万人群逐条广播无差别 Push。 |
| @提醒 | 被 @ 用户离线或后台 | 被 @ 用户 user_id,高优先级。 |
| 好友申请/审批 | 目标用户离线 | 目标用户 user_id。 |
| 群申请/邀请/审批 | 审批人或目标成员离线 | 对应用户 user_id。 |
| 系统通知 | 已写入系统通知表且用户离线 | 通知目标 user_id。 |
| 语音/视频来电 | 被叫方当前无在线可响铃设备或 App 后台 | 被叫 user_id,短 TTL。 |
| 未接来电 | 通话超时、取消或未接 | 被叫 user_id。 |
### 5.2 在线与离线判断
在线实时消息仍走 WebSocket。Push 不是消息正文真源,只负责提醒。客户端重连后必须按 Topic `seq` 或业务 ID 从 IM Server 拉取补偿,不能只依赖 Push payload 展示最终状态。
推荐判断:
- 当前用户存在可投递在线会话:优先 WS,下发 Push 可按用户设置降级或不发。
- 用户全离线:生成 Push 任务。
- 用户在线但 App 后台状态不可判定:可生成低干扰 Push,客户端本地去重。
- 群万人场景:实时 fanout 走 Redis/Kafka/Topic 路由,离线只对需要提醒的成员生成 Push。
### 5.3 任务状态机
```text
pending -> sending -> sent
pending -> sending -> retry_wait -> sending
pending -> sending -> failed
pending -> skipped
```
| 状态 | 说明 |
| --- | --- |
| `pending` | 已生成,等待 worker 发送。 |
| `sending` | worker 已领取,正在请求极光。 |
| `sent` | 极光 API 返回成功并记录 `msg_id`。 |
| `retry_wait` | 临时错误,等待退避重试。 |
| `failed` | 永久失败或超过最大重试次数。 |
| `skipped` | 用户免打扰、无有效设备、消息已过期或策略不允许发送。 |
任务需保存 `dedupe_key`,例如 `tenant_code:user_id:topic:seq:push_type`,避免重复生成离线提醒。
## 6. 服务端调用极光 REST API
极光创建推送 API:
```http
POST https://api.jpush.cn/v3/push
Authorization: Basic base64(app_key + ":" + master_secret)
Content-Type: application/json
```
官方说明中,创建推送 API 使用 HTTPS、HTTP Basic Authentication 和 JSON 请求体;推送目标支持 `alias`、`registration_id`、`tag` 等方式,`alias` 单次最多 1000 个,`registration_id` 单次最多 1000 个;返回成功时包含 `sendno` 和 `msg_id`。
### 6.1 普通离线消息 Push
```json
{
"platform": ["android", "ios", "hmos"],
"audience": {
"alias": ["usr_target"]
},
"notification": {
"alert": "你收到一条新消息",
"android": {
"title": "MeetingIM",
"alert": "你收到一条新消息",
"extras": {
"type": "im_message",
"tenant_code": "default",
"topic": "p2p...",
"seq": "128",
"sender_id": "usr_sender",
"message_type": "text"
}
},
"ios": {
"alert": {
"title": "MeetingIM",
"body": "你收到一条新消息"
},
"sound": "default",
"badge": "+1",
"extras": {
"type": "im_message",
"tenant_code": "default",
"topic": "p2p...",
"seq": "128",
"sender_id": "usr_sender",
"message_type": "text"
}
},
"hmos": {
"title": "MeetingIM",
"alert": "你收到一条新消息",
"category": "IM",
"extras": {
"type": "im_message",
"tenant_code": "default",
"topic": "p2p...",
"seq": "128",
"sender_id": "usr_sender",
"message_type": "text"
}
}
},
"options": {
"time_to_live": 86400,
"apns_production": false,
"classification": 1
}
}
```
### 6.2 群消息 Push
群消息 Push 只提醒,不携带完整消息正文。万人群不建议按群全员同步投递,只对离线且需要提醒的人生成任务,例如被 @、特别关注、管理员公告、未免打扰小群等。
```json
{
"platform": "all",
"audience": {
"alias": ["usr_mentioned"]
},
"notification": {
"alert": "群里有人提到了你",
"android": {
"title": "项目群",
"alert": "群里有人提到了你",
"extras": {
"type": "group_mention",
"tenant_code": "default",
"topic": "grp...",
"seq": "56001",
"sender_id": "usr_sender",
"mention": "1"
}
},
"ios": {
"alert": {
"title": "项目群",
"body": "群里有人提到了你"
},
"badge": "+1",
"sound": "default",
"extras": {
"type": "group_mention",
"tenant_code": "default",
"topic": "grp...",
"seq": "56001",
"sender_id": "usr_sender",
"mention": "1"
}
}
},
"options": {
"time_to_live": 86400,
"apns_production": false,
"classification": 1
}
}
```
### 6.3 来电 Push
语音/视频来电需要短 TTL。普通离线 Push 只做提醒;如后续要实现系统级强提醒、VoIP 样式或厂商 VoIP,需要额外开通并按平台单独配置。
```json
{
"platform": "all",
"audience": {
"alias": ["usr_callee"]
},
"notification": {
"alert": "收到一通语音通话",
"android": {
"title": "语音通话",
"alert": "张三邀请你语音通话",
"extras": {
"type": "call_invite",
"tenant_code": "default",
"topic": "p2p...",
"seq": "30",
"call_id": "call_01K...",
"call_type": "audio",
"caller_id": "usr_caller"
}
},
"ios": {
"alert": {
"title": "语音通话",
"body": "张三邀请你语音通话"
},
"sound": "default",
"badge": "+1",
"extras": {
"type": "call_invite",
"tenant_code": "default",
"topic": "p2p...",
"seq": "30",
"call_id": "call_01K...",
"call_type": "audio",
"caller_id": "usr_caller"
}
}
},
"options": {
"time_to_live": 60,
"apns_production": false,
"classification": 1
}
}
```
## 7. 客户端点击与补偿拉取
客户端收到或点击 Push 后按 `extras.type` 分发:
| `extras.type` | 客户端动作 |
| --- | --- |
| `im_message` | 打开 `topic` 对应会话,按本地最后 `seq + 1` 拉取消息。 |
| `group_mention` | 打开群会话并定位到 `seq`,若本地无该消息先拉取。 |
| `call_invite` | 如果通话仍有效,打开来电页;同时通过 IM 登录和会话补偿确认通话状态。 |
| `call_missed` | 打开通话记录或对应会话。 |
| `system_notification` | 打开系统消息列表或 `action` 指定页面,再调用 HTTP 拉取详情。 |
| `friend_request` | 打开新朋友列表并刷新未处理数。 |
| `group_request` | 打开群审批入口并刷新列表。 |
Push 中的 `topic`、`seq`、`call_id` 只用于定位和补偿,不作为业务真源。客户端必须重新登录 IM 并拉取服务端数据确认状态,例如通话是否已取消、消息是否已撤回、系统通知是否已读。
## 8. 隐私与安全
1. `jpush_master_secret` 只在后端配置和请求极光时使用,不返回客户端。
2. Push 通知栏默认不展示敏感正文,可按用户隐私设置决定是否展示摘要。
3. `extras` 不放身份证号、手机号、文件直链、完整消息正文、审核原因明细等敏感数据。
4. 日志只记录 `task_id/user_id/provider/status/msg_id/error_code`,不记录完整 Push payload。
5. 推送失败后按错误类型禁用无效 registration_id,避免持续打失败请求。
6. 多租户场景下 `tenant_code` 必须进入任务、payload、dedupe_key 和日志,禁止跨租户复用设备 token。
## 9. 联调验收
| 验收项 | 期望结果 |
| --- | --- |
| 客户端初始化 | SDK 返回 registration_id,alias 绑定为 `user_id.replace("-", ".").replace("_", "|")`。 |
| 设备上报 | `PUT /v1/im/devices/{device_id}/push-token` 返回成功,服务端记录 provider=`jpush`。 |
| 普通离线消息 | 用户离线后收到 Push,点击后进入会话并补齐 Topic seq。 |
| 群 @ 提醒 | 被 @ 用户离线时只收到一次提醒,重连后定位到对应消息。 |
| 语音来电 | 被叫离线时收到短 TTL 来电 Push,通话取消后点击不会进入过期通话。 |
| 免打扰 | 免打扰会话不产生普通 Push,@ 或强提醒按策略例外。 |
| 幂等重试 | 同一 `dedupe_key` 不重复发,极光临时失败可重试。 |
| 无效设备 | 极光返回无效 token 后设备记录被禁用或待清理。 |
| iOS 环境 | 测试包 `apns_production=false`,生产包为 true。 |