326 lines
8.9 KiB
Markdown
326 lines
8.9 KiB
Markdown
# 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。
|
||
|
||
极光 alias 不支持中横线 `-` 和下划线 `_`,而 IM `user_id` 可能包含这两个字符。客户端和后端统一使用以下映射:
|
||
|
||
```text
|
||
jpush_alias = user_id.replace("-", ".").replace("_", "|")
|
||
```
|
||
|
||
示例:`usrd6Ag5opa-ww` 对应极光 alias `usrd6Ag5opa.ww`。
|
||
|
||
### 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.replace("-", ".").replace("_", "|")` | 极光控制台能查到别名或设备。 |
|
||
| 3 | 调用设备上报接口 | 服务端设备记录 provider=`jpush`。 |
|
||
| 4 | 目标用户退出或断网 | IM 判断为离线或不可 WS 投递。 |
|
||
| 5 | 发送 P2P 消息 | 离线用户收到 Push。 |
|
||
| 6 | 点击 Push | App 打开对应会话并补齐 `seq`。 |
|
||
| 7 | 发起语音/视频通话 | 离线被叫收到短 TTL 来电 Push。 |
|
||
| 8 | 通话取消后点击旧 Push | 客户端查询后显示已取消或未接,不进入通话中。 |
|
||
| 9 | 关闭会话免打扰 | 普通消息不发 Push,@提醒按策略执行。 |
|
||
| 10 | 极光返回无效 token | 后端禁用设备 token,重新上报后恢复。 |
|