feat: add jpush push handler
This commit is contained in:
@@ -446,6 +446,138 @@ X-MeetingIM-APIKey: <预置的普通 API Key>
|
||||
| 消息过大 | `{"ctrl":{"id":"pub-1","code":413,"text":"message too large","params":{"reason":"MESSAGE_TOO_LARGE","max_size":4194304}}}` | 禁止重试,提示压缩或拆分 |
|
||||
| 断线 | WebSocket close | 指数退避重连,重新 `hi -> token login -> sub me -> sub topics`,按最后完整 `seq + 1` 增量拉取 |
|
||||
|
||||
##### 0.5.4.9 极光离线 Push 与重连补偿
|
||||
|
||||
离线 Push 只承担提醒和唤醒 App,不作为消息正文或业务状态真源。客户端收到极光 Push 后,必须重新登录 IM,通过 `topic + seq`、`call_id` 或系统通知 ID 拉取服务端状态。普通聊天、群 @、系统通知、好友/群审批、音视频来电都复用同一套 extras 分发协议。
|
||||
|
||||
客户端侧要求:
|
||||
|
||||
- App 集成 JPush SDK,初始化使用极光 `AppKey`,不接触 `MasterSecret`。
|
||||
- 登录 IM 后将极光 alias 绑定为当前 `user_id`,例如 `usr...`;同一用户多设备允许绑定同一个 alias。
|
||||
- SDK 返回 `registration_id` 后调用 `PUT /v1/im/devices/{device_id}/push-token` 上报,`provider` 固定传 `jpush`。
|
||||
- 点击 Push 后按 `extras.type` 跳转,再按服务端数据补偿,不能只凭 Push payload 渲染最终状态。
|
||||
|
||||
服务端侧要求:
|
||||
|
||||
- `jpush_master_secret` 只保存在后台配置 `im_jpush` 分组,IM Server 通过内部配置接口读取并调用极光 REST API。
|
||||
- 用户在线时优先 WebSocket 实时投递;用户离线、后台或不可投递时生成 Push 任务。
|
||||
- 万人大群实时 fanout 不靠 Push;离线只对需要提醒的成员生成极光 Push,客户端重连后按 Topic seq 拉取补偿。
|
||||
- Push payload 默认不带敏感正文,通知栏文案按用户隐私设置降级。
|
||||
|
||||
极光 Push extras 统一格式:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "im_message",
|
||||
"tenant_code": "default",
|
||||
"topic": "p2p...",
|
||||
"seq": "128",
|
||||
"sender_id": "usr_sender",
|
||||
"message_type": "text"
|
||||
}
|
||||
```
|
||||
|
||||
| `extras.type` | 必填字段 | 客户端动作 |
|
||||
| --- | --- | --- |
|
||||
| `im_message` | `tenant_code,topic,seq` | 打开会话,按本地最后 seq 补齐消息并定位。 |
|
||||
| `group_mention` | `tenant_code,topic,seq,sender_id` | 打开群会话并定位被 @ 消息。 |
|
||||
| `call_invite` | `tenant_code,topic,seq,call_id,call_type,caller_id` | 打开来电页前先登录 IM 并确认通话仍为有效来电。 |
|
||||
| `call_missed` | `tenant_code,topic,call_id` | 打开通话记录或对应会话。 |
|
||||
| `system_notification` | `tenant_code,notification_id` | 打开系统消息列表并刷新详情。 |
|
||||
| `friend_request` | `tenant_code,request_id` | 打开新朋友列表并刷新未处理数。 |
|
||||
| `group_request` | `tenant_code,topic,request_id` | 打开群审批入口并刷新列表。 |
|
||||
|
||||
普通离线消息极光 payload 示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"platform": "all",
|
||||
"audience": {
|
||||
"alias": ["usr_target"]
|
||||
},
|
||||
"notification": {
|
||||
"alert": "你收到一条新消息",
|
||||
"android": {
|
||||
"title": "MeetingIM",
|
||||
"alert": "你收到一条新消息",
|
||||
"extras": {
|
||||
"type": "im_message",
|
||||
"tenant_code": "default",
|
||||
"topic": "p2p...",
|
||||
"seq": "128"
|
||||
}
|
||||
},
|
||||
"ios": {
|
||||
"alert": {
|
||||
"title": "MeetingIM",
|
||||
"body": "你收到一条新消息"
|
||||
},
|
||||
"sound": "default",
|
||||
"badge": "+1",
|
||||
"extras": {
|
||||
"type": "im_message",
|
||||
"tenant_code": "default",
|
||||
"topic": "p2p...",
|
||||
"seq": "128"
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"time_to_live": 86400,
|
||||
"apns_production": false,
|
||||
"classification": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
音视频来电极光 payload 示例:
|
||||
|
||||
```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
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 0.5.5 Long Polling 与文件基础示例
|
||||
|
||||
|
||||
@@ -0,0 +1,317 @@
|
||||
# IM 极光推送前后端对接文档
|
||||
|
||||
更新时间:2026-09-04
|
||||
|
||||
## 1. 对接边界
|
||||
|
||||
极光 JPush 接入分三段:
|
||||
|
||||
| 边界 | 责任 |
|
||||
| --- | --- |
|
||||
| 客户端和极光 SDK | 初始化 SDK、申请通知权限、获取 `registration_id`、绑定 alias、接收和点击 Push。 |
|
||||
| 客户端和 IM Server | 登录后上报设备 Push Token,收到 Push 后按 `topic/seq/call_id` 回 IM 拉取补偿。 |
|
||||
| IM Server 和极光 REST API | 保存 `master_secret`,生成 Push 任务,调用 `POST /v3/push`,记录 `msg_id` 和失败原因。 |
|
||||
|
||||
客户端不需要知道 `master_secret`,也不直接调用极光 REST API。
|
||||
|
||||
## 2. 客户端接入
|
||||
|
||||
### 2.1 SDK 初始化
|
||||
|
||||
客户端按平台集成 JPush SDK:
|
||||
|
||||
- Android:初始化 JPush SDK,创建通知 Channel,按厂商通道要求配置包名、签名、Channel ID。
|
||||
- iOS:配置 APNs 证书或 Token Authentication,申请通知权限。
|
||||
- HarmonyOS:按鸿蒙 SDK 文档初始化并配置通知分类。
|
||||
|
||||
客户端启动后取得 `registration_id`,登录 IM 后把 alias 绑定为当前 `user_id`。同一用户多设备允许绑定同一个 alias。
|
||||
|
||||
### 2.2 上报 Push Token
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
请求:
|
||||
|
||||
```json
|
||||
{
|
||||
"provider": "jpush",
|
||||
"token": "registration_id",
|
||||
"platform": "ios",
|
||||
"app_version": "1.0.0",
|
||||
"push_env": "test",
|
||||
"sdk_version": "5.0.0",
|
||||
"notification_permission": "granted"
|
||||
}
|
||||
```
|
||||
|
||||
响应 `data`:
|
||||
|
||||
```json
|
||||
{
|
||||
"device_id": "ios_device_1",
|
||||
"provider": "jpush",
|
||||
"platform": "ios",
|
||||
"app_version": "1.0.0",
|
||||
"updated_at": "2026-09-04T10:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
字段说明:
|
||||
|
||||
| 字段 | 必填 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `provider` | 是 | 固定传 `jpush`。后续保留 `fcm`、`apns` 等兼容值。 |
|
||||
| `token` | 是 | 极光 SDK 返回的 `registration_id`。 |
|
||||
| `platform` | 是 | `android`、`ios`、`hmos`。 |
|
||||
| `app_version` | 否 | 客户端版本,用于排查。 |
|
||||
| `push_env` | 否 | `test` 或 `production`,用于 iOS APNs 环境核对。 |
|
||||
| `sdk_version` | 否 | JPush SDK 版本。 |
|
||||
| `notification_permission` | 否 | `granted`、`denied`、`unknown`。 |
|
||||
|
||||
### 2.3 点击 Push 后处理
|
||||
|
||||
客户端统一读取 `extras`:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "im_message",
|
||||
"tenant_code": "default",
|
||||
"topic": "p2p...",
|
||||
"seq": "128",
|
||||
"sender_id": "usr_sender",
|
||||
"message_type": "text"
|
||||
}
|
||||
```
|
||||
|
||||
处理规则:
|
||||
|
||||
1. 如果未登录,先进入登录或静默登录。
|
||||
2. 如果租户不一致,先切换到 `tenant_code`。
|
||||
3. 按 `type` 跳转目标页面。
|
||||
4. 按 `topic` 和本地游标拉取消息补偿。
|
||||
5. 按 `seq` 定位消息;若消息已撤回,展示撤回占位。
|
||||
6. 对通话类 Push,必须向 IM Server 查询当前通话状态,不能只凭 Push 打开通话中页面。
|
||||
|
||||
## 3. 后端接入
|
||||
|
||||
### 3.1 配置读取
|
||||
|
||||
IM Server 从后台配置读取 `im_jpush` 分组:
|
||||
|
||||
```json
|
||||
{
|
||||
"jpush_enabled": "true",
|
||||
"jpush_app_key": "app_key",
|
||||
"jpush_master_secret": "******",
|
||||
"jpush_api_domain": "https://api.jpush.cn",
|
||||
"jpush_apns_production": "false",
|
||||
"jpush_default_ttl_seconds": "86400",
|
||||
"jpush_call_ttl_seconds": "60",
|
||||
"jpush_use_alias": "true",
|
||||
"jpush_test_model": "false",
|
||||
"jpush_classification": "1"
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 设备记录
|
||||
|
||||
设备表建议至少支持:
|
||||
|
||||
| 字段 | 说明 |
|
||||
| --- | --- |
|
||||
| `user_id` | IM 用户 ID。 |
|
||||
| `device_id` | 客户端设备 ID。 |
|
||||
| `provider` | `jpush`。 |
|
||||
| `push_token` | 极光 `registration_id`。 |
|
||||
| `platform` | `android/ios/hmos`。 |
|
||||
| `app_version` | App 版本。 |
|
||||
| `push_env` | `test/production`。 |
|
||||
| `enabled` | 是否有效。 |
|
||||
| `last_seen_at` | 最近上报时间。 |
|
||||
| `disabled_reason` | 禁用原因。 |
|
||||
|
||||
同一 `user_id + device_id + provider` 覆盖更新;同一 token 换绑账号时,以最后一次登录上报为准并禁用旧绑定。
|
||||
|
||||
### 3.3 Push 任务
|
||||
|
||||
服务端生成任务时推荐数据结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"task_id": "push_01K...",
|
||||
"tenant_code": "default",
|
||||
"target_user_id": "usr_target",
|
||||
"push_type": "im_message",
|
||||
"topic": "p2p...",
|
||||
"seq": 128,
|
||||
"call_id": "",
|
||||
"dedupe_key": "default:usr_target:p2p...:128:im_message",
|
||||
"status": "pending",
|
||||
"retry_count": 0,
|
||||
"next_retry_at": "2026-09-04T10:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
任务落库或投 Kafka 后由 worker 发送。极光成功返回后记录 `msg_id`;失败按错误类型重试、跳过或禁用设备。
|
||||
|
||||
## 4. IM Server 调极光
|
||||
|
||||
### 4.1 请求
|
||||
|
||||
```http
|
||||
POST https://api.jpush.cn/v3/push
|
||||
Authorization: Basic base64(app_key + ":" + master_secret)
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
普通消息:
|
||||
|
||||
```json
|
||||
{
|
||||
"platform": "all",
|
||||
"audience": {
|
||||
"alias": ["usr_target"]
|
||||
},
|
||||
"notification": {
|
||||
"alert": "你收到一条新消息",
|
||||
"android": {
|
||||
"title": "MeetingIM",
|
||||
"alert": "你收到一条新消息",
|
||||
"extras": {
|
||||
"type": "im_message",
|
||||
"tenant_code": "default",
|
||||
"topic": "p2p...",
|
||||
"seq": "128"
|
||||
}
|
||||
},
|
||||
"ios": {
|
||||
"alert": {
|
||||
"title": "MeetingIM",
|
||||
"body": "你收到一条新消息"
|
||||
},
|
||||
"sound": "default",
|
||||
"badge": "+1",
|
||||
"extras": {
|
||||
"type": "im_message",
|
||||
"tenant_code": "default",
|
||||
"topic": "p2p...",
|
||||
"seq": "128"
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"time_to_live": 86400,
|
||||
"apns_production": false,
|
||||
"classification": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
来电提醒:
|
||||
|
||||
```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": "video",
|
||||
"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": "video",
|
||||
"caller_id": "usr_caller"
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"time_to_live": 60,
|
||||
"apns_production": false,
|
||||
"classification": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 响应处理
|
||||
|
||||
成功响应示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"sendno": "0",
|
||||
"msg_id": "18100287008546343"
|
||||
}
|
||||
```
|
||||
|
||||
处理规则:
|
||||
|
||||
- HTTP 200 且返回 `msg_id`:任务置为 `sent`。
|
||||
- 网络超时、5xx、限流:任务置为 `retry_wait`,按退避重试。
|
||||
- 鉴权失败或配置错误:任务置为 `failed`,告警并停止继续重试同配置。
|
||||
- registration_id 无效:禁用对应设备 token。
|
||||
- 用户关闭通知权限:记录设备能力,后续可跳过普通提醒。
|
||||
|
||||
## 5. Push extras 规范
|
||||
|
||||
所有 extras 值建议使用字符串,避免不同平台 SDK 对数字类型解析不一致。
|
||||
|
||||
| 字段 | 必填 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `type` | 是 | `im_message`、`group_mention`、`call_invite`、`call_missed`、`system_notification`、`friend_request`、`group_request`。 |
|
||||
| `tenant_code` | 是 | 租户编码。 |
|
||||
| `topic` | 条件 | 会话或群 Topic。消息、群、通话类必填。 |
|
||||
| `seq` | 条件 | Topic 消息序号。消息、群、通话类建议必填。 |
|
||||
| `call_id` | 条件 | 通话类必填。 |
|
||||
| `call_type` | 条件 | `audio` 或 `video`。 |
|
||||
| `sender_id` | 否 | 消息发送人。 |
|
||||
| `caller_id` | 条件 | 来电类必填。 |
|
||||
| `notification_id` | 条件 | 系统通知类必填。 |
|
||||
| `route` | 否 | 客户端白名单路由,不允许外部 URL。 |
|
||||
|
||||
## 6. 前后端联调清单
|
||||
|
||||
| 步骤 | 操作 | 验证 |
|
||||
| --- | --- | --- |
|
||||
| 1 | 客户端初始化 JPush SDK | 能拿到 `registration_id`。 |
|
||||
| 2 | 登录 IM 并绑定 alias=`user_id` | 极光控制台能查到别名或设备。 |
|
||||
| 3 | 调用设备上报接口 | 服务端设备记录 provider=`jpush`。 |
|
||||
| 4 | 目标用户退出或断网 | IM 判断为离线或不可 WS 投递。 |
|
||||
| 5 | 发送 P2P 消息 | 离线用户收到 Push。 |
|
||||
| 6 | 点击 Push | App 打开对应会话并补齐 `seq`。 |
|
||||
| 7 | 发起语音/视频通话 | 离线被叫收到短 TTL 来电 Push。 |
|
||||
| 8 | 通话取消后点击旧 Push | 客户端查询后显示已取消或未接,不进入通话中。 |
|
||||
| 9 | 关闭会话免打扰 | 普通消息不发 Push,@提醒按策略执行。 |
|
||||
| 10 | 极光返回无效 token | 后端禁用设备 token,重新上报后恢复。 |
|
||||
@@ -0,0 +1,368 @@
|
||||
# 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=user_id 投递。 |
|
||||
| `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`,例如 `usr...`。
|
||||
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 绑定为当前 `usr...`。 |
|
||||
| 设备上报 | `PUT /v1/im/devices/{device_id}/push-token` 返回成功,服务端记录 provider=`jpush`。 |
|
||||
| 普通离线消息 | 用户离线后收到 Push,点击后进入会话并补齐 Topic seq。 |
|
||||
| 群 @ 提醒 | 被 @ 用户离线时只收到一次提醒,重连后定位到对应消息。 |
|
||||
| 语音来电 | 被叫离线时收到短 TTL 来电 Push,通话取消后点击不会进入过期通话。 |
|
||||
| 免打扰 | 免打扰会话不产生普通 Push,@ 或强提醒按策略例外。 |
|
||||
| 幂等重试 | 同一 `dedupe_key` 不重复发,极光临时失败可重试。 |
|
||||
| 无效设备 | 极光返回无效 token 后设备记录被禁用或待清理。 |
|
||||
| iOS 环境 | 测试包 `apns_production=false`,生产包为 true。 |
|
||||
Reference in New Issue
Block a user