- 新增 Android SDK 使用文档,包含模块结构、集成方式和快速开始指南 - 添加 SDK API 重设计规范,统一初始化和登录接口设计 - 补充安全设计规范,完善 UserSig 鉴权和敏感数据处理方案 - 创建平台 REST API 规范,定义服务端到服务端的调用接口 - 添加离线推送架构设计,集成各大厂商推送服务与 IM 联动方案
18 KiB
18 KiB
XuqmGroup Server 联调接口文档
最后更新:2026-04-28
线上入口
| 服务 | 地址 | 说明 |
|---|---|---|
| 租户服务 | https://dev.xuqinmin.com/api/ |
认证、应用、子账号、运营平台 |
| IM HTTP | https://dev.xuqinmin.com/api/im/ |
IM 登录、消息发送、撤回、历史消息 |
| IM WebSocket | wss://dev.xuqinmin.com/ws/im |
实时消息 |
| 文件服务 | https://file.dev.xuqinmin.com/api/file/ |
文件上传、下载、缩略图 |
| App 更新 | https://dev.xuqinmin.com/api/v1/updates/ |
原生版本管理 |
| RN 热更新 | https://dev.xuqinmin.com/api/v1/rn/ |
Bundle 热更新 |
ID 约定
这套工程里同时存在两种“应用标识”,不要混用:
| 名称 | 含义 | 常见位置 |
|---|---|---|
tenant appId |
租户平台应用主键,tenant-service 的 /api/apps/{id}、/api/apps/{appId}/services 使用它 |
租户平台、服务配置页 |
IM appKey |
IM 业务域作用域标识,im-service 的管理接口和消息接口虽然参数名仍叫 appId,但实际传的是这个值 |
IM 管理页、IM HTTP 接口 |
结论:
tenant-platform的“服务配置”只认租户app.idtenant-platform的“IM 管理”必须带appKeyim-service代码里沿用旧参数名appId,但这是历史命名,调用方传的是appKey
初始化管理员账号
| 字段 | 值 |
|---|---|
| 用户名 | admin |
| 初始密码 | Admin@123456 |
| 登录接口 | POST /api/auth/ops/login |
统一响应
{
"code": 200,
"status": "0",
"data": {},
"message": "success"
}
常见错误码
code |
status |
说明 |
|---|---|---|
200 |
"0" |
成功 |
400 |
"1" |
参数校验失败或请求不合法 |
401 |
"1" |
未登录、Token 无效或已过期 |
403 |
"1" |
无权限访问 |
500 |
"1" |
服务端内部错误 |
鉴权规则
| 场景 | 鉴权方式 |
|---|---|
| 租户平台接口 | Authorization: Bearer <tenant_jwt> |
| 运营平台接口 | Authorization: Bearer <ops_jwt> |
| IM HTTP 接口 | Authorization: Bearer <im_jwt> |
| IM WebSocket | ?token=<im_jwt> |
| App 更新检查 | 无需登录 |
| RN 更新检查 | 无需登录 |
| Bundle 下载 | 无需登录 |
核心接口清单
tenant-service
| 方法 | 路径 | 鉴权 | 说明 |
|---|---|---|---|
| GET | /api/auth/captcha |
否 | 获取图形验证码 |
| POST | /api/auth/send-email-code |
否 | 发送邮箱验证码 |
| POST | /api/auth/register |
否 | 注册主账号 |
| POST | /api/auth/login |
否 | 租户登录 |
| POST | /api/auth/forgot-password |
否 | 发送找回密码邮件 |
| POST | /api/auth/reset-password |
否 | 重置密码 |
| GET | /api/apps |
是 | 应用列表 |
| GET | /api/apps/{id} |
是 | 应用详情 |
| POST | /api/apps |
是 | 创建应用 |
| PUT | /api/apps/{id} |
是 | 更新应用 |
| DELETE | /api/apps/{id} |
是 | 删除应用 |
| GET | /api/apps/{appId}/services |
是 | 服务列表 |
| POST | /api/apps/{appId}/services/toggle |
是 | 开关服务 |
| POST | /api/apps/{appId}/services/{id}/regenerate-key |
是 | 重新生成服务密钥 |
| GET | /api/sub-accounts |
是 | 子账号列表 |
| POST | /api/sub-accounts/send-verify-code |
是 | 子账号邮箱验证码 |
| POST | /api/sub-accounts/verify-email |
是 | 校验子账号邮箱 |
| POST | /api/sub-accounts |
是 | 创建子账号 |
| DELETE | /api/sub-accounts/{id} |
是 | 禁用子账号 |
| POST | /api/auth/ops/login |
否 | 运营管理员登录 |
| GET | /api/ops/tenants |
是 | 运营租户列表 |
| POST | /api/ops/tenants/{id}/toggle-status |
是 | 租户启停 |
| GET | /api/ops/statistics |
是 | 统计面板 |
im-service
| 方法 | 路径 | 鉴权 | 说明 |
|---|---|---|---|
| POST | /api/im/auth/login |
否 | 获取 IM Token;需要 X-App-Timestamp / X-App-Nonce / X-App-Signature |
| GET | /api/im/accounts/{userId} |
是 | 查询用户资料 |
| PUT | /api/im/accounts/{userId} |
是 | 更新自己的资料 |
| GET | /api/im/accounts/search |
否 | 搜索账号 |
| POST | /api/im/accounts/import |
是 | 导入单个账号 |
| POST | /api/im/accounts/import/batch |
是 | 批量导入账号 |
| DELETE | /api/im/accounts/{userId} |
是 | 删除账号 |
| GET | /api/im/accounts/{userId}/exists |
是 | 检查账号是否存在 |
| GET | /api/im/groups/{groupId}/members |
是 | 查询群成员列表 |
| GET | /api/im/groups/{groupId}/members/search |
是 | 搜索群成员 |
| POST | /api/im/messages/send |
是 | 发送消息(TEXT / IMAGE / AUDIO / VIDEO / FILE / LOCATION / CUSTOM / NOTIFY / RICH_TEXT / CALL_AUDIO / CALL_VIDEO / FORWARD / QUOTE / MERGE) |
| GET | /api/im/messages/search |
是 | 云端消息搜索 |
| PUT | /api/im/messages/{id} |
是 | 编辑自己发送的文本消息 |
| POST | /api/im/messages/{id}/revoke |
是 | 撤回消息 |
| GET | /api/im/messages/history/{toId} |
是 | 查询历史消息 |
| WS | /ws/im |
IM Token | 建立实时连接 |
push-service
| 方法 | 路径 | 鉴权 | 说明 |
|---|---|---|---|
| POST | /api/push/register |
是 | 注册设备 token |
| POST | /api/push/receive-push |
是 | 开启或关闭接收推送 |
| POST | /api/push/send |
是 | 发送推送通知 |
file-service
| 方法 | 路径 | 鉴权 | 说明 |
|---|---|---|---|
| POST | /api/file/upload |
是 | 文件上传,按 SHA-256 去重 |
| GET | /api/file/{hash} |
否 | 按 hash 获取文件 |
| GET | /api/file/{hash}/thumbnail |
否 | 按 hash 获取缩略图 |
update-service
| 方法 | 路径 | 鉴权 | 说明 |
|---|---|---|---|
| GET | /api/v1/updates/app/check |
否 | 检查 App 更新 |
| POST | /api/v1/updates/app/upload |
是 | 上传 App 版本,支持即时发布 / 定时发布 / 市场提交配置;Harmony 版本仅保存市场链接,不提供本地安装包下载 |
| POST | /api/v1/updates/app/{id}/publish |
是 | 发布 App 版本 |
| GET | /api/v1/updates/app/list |
是 | App 版本列表 |
| GET | /api/v1/updates/files/apk/{filename} |
否 | 下载 APK |
| GET | /api/v1/rn/update/check |
否 | 检查 RN 热更新 |
| POST | /api/v1/rn/upload |
是 | 上传 Bundle |
| POST | /api/v1/rn/{id}/publish |
是 | 发布 Bundle |
| GET | /api/v1/rn/files/{appId}/{platform}/{moduleId} |
否 | 下载 Bundle |
说明:这里的 appId 按 appKey 解析。当前 demo 默认使用 ak_demo_chat,tenant-service 会优先复用数据库里已有的应用;如果没有,会自动补一条默认 demo 应用和基础服务配置。POST /api/im/auth/login 还要求 demo-service 通过 AppSecret 生成签名头再转发给 IM 服务。
curl 示例
运营平台登录
curl -X POST 'https://dev.xuqinmin.com/api/auth/ops/login' \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"Admin@123456"}'
App 更新检查
curl 'https://dev.xuqinmin.com/api/v1/updates/app/check?appId=ak_demo_chat&platform=ANDROID¤tVersionCode=1'
curl 'https://dev.xuqinmin.com/api/v1/updates/app/check?appId=ak_demo_chat&platform=HARMONY¤tVersionCode=1'
Harmony 平台只跳转应用市场,不提供本地安装包下载。
RN 热更新检查
curl 'https://dev.xuqinmin.com/api/v1/rn/update/check?appId=ak_demo_chat&platform=ANDROID&moduleId=chat-home¤tVersion=1.0.0'
IM 登录
curl -X POST 'https://dev.xuqinmin.com/api/im/auth/login?appId=ak_demo_chat&userId=demo_alice'
返回示例中的 data 会同时包含 token 和 expiresAt,用于客户端提前做静默续签。
Demo IM 刷新
curl -X POST 'https://dev.xuqinmin.com/api/demo/auth/refresh-im?appId=ak_demo_chat' \
-H 'Authorization: Bearer <demo_jwt>'
该接口会基于 demo 登录态重新签发 IM token,并返回新的 expiresAt。
IM 会话与关系链
curl 'https://dev.xuqinmin.com/api/im/accounts/user_001?appId=ak_demo_chat'
curl -X POST 'https://dev.xuqinmin.com/api/im/accounts/import?appId=ak_demo_chat' \
-H 'Content-Type: application/json' \
-d '{"userId":"user_001","nickname":"Alice"}'
curl -X POST 'https://dev.xuqinmin.com/api/im/accounts/import/batch?appId=ak_demo_chat' \
-H 'Content-Type: application/json' \
-d '[{"userId":"user_001"},{"userId":"user_002"}]'
curl -X DELETE 'https://dev.xuqinmin.com/api/im/accounts/user_001?appId=ak_demo_chat'
curl 'https://dev.xuqinmin.com/api/im/accounts/user_001/exists?appId=ak_demo_chat'
curl 'https://dev.xuqinmin.com/api/im/conversations?appId=ak_demo_chat'
curl -X PUT 'https://dev.xuqinmin.com/api/im/conversations/user_002/pinned?appId=ak_demo_chat&chatType=SINGLE&pinned=true'
curl -X PUT 'https://dev.xuqinmin.com/api/im/conversations/user_002/draft?appId=ak_demo_chat&chatType=SINGLE&draft=hello'
curl -X DELETE 'https://dev.xuqinmin.com/api/im/conversations/user_002?appId=ak_demo_chat&chatType=SINGLE'
curl 'https://dev.xuqinmin.com/api/im/groups?appId=ak_demo_chat'
curl 'https://dev.xuqinmin.com/api/im/groups/public?appId=ak_demo_chat&keyword=demo'
curl 'https://dev.xuqinmin.com/api/im/groups/search?appId=ak_demo_chat&keyword=demo&size=20'
curl 'https://dev.xuqinmin.com/api/im/groups/group_001/members?appId=ak_demo_chat'
curl 'https://dev.xuqinmin.com/api/im/groups/group_001/members/search?appId=ak_demo_chat&keyword=demo&size=20'
curl 'https://dev.xuqinmin.com/api/im/messages/search?appId=ak_demo_chat&keyword=hello&page=0&size=20'
curl 'https://dev.xuqinmin.com/api/im/admin/webhooks?appId=ak_demo_chat'
curl -X POST 'https://dev.xuqinmin.com/api/im/groups/group_001/join-requests?appId=ak_demo_chat&remark=申请加入'
curl 'https://dev.xuqinmin.com/api/im/groups/group_001/join-requests?appId=ak_demo_chat'
curl -X POST 'https://dev.xuqinmin.com/api/im/groups/group_001/join-requests/req_001/accept?appId=ak_demo_chat'
curl -X POST 'https://dev.xuqinmin.com/api/im/groups/group_001/join-requests/req_001/reject?appId=ak_demo_chat'
curl 'https://dev.xuqinmin.com/api/im/blacklist?appId=ak_demo_chat'
curl 'https://dev.xuqinmin.com/api/im/friend-requests?appId=ak_demo_chat&direction=incoming'
IM 管理后台接口
curl 'https://dev.xuqinmin.com/api/im/admin/users?appId=ak_demo_chat&page=0&size=20'
curl 'https://dev.xuqinmin.com/api/im/admin/groups?appId=ak_demo_chat'
curl 'https://dev.xuqinmin.com/api/im/admin/messages?appId=ak_demo_chat&userA=user_001&userB=user_002&page=0&size=20'
curl 'https://dev.xuqinmin.com/api/im/admin/operation-logs?appId=ak_demo_chat&page=0&size=20'
curl -X POST 'https://dev.xuqinmin.com/api/im/admin/messages/msg_001/revoke?appId=ak_demo_chat'
curl -X DELETE 'https://dev.xuqinmin.com/api/im/admin/groups/group_001'
curl 'https://dev.xuqinmin.com/api/im/admin/friend-requests?appId=ak_demo_chat'
curl -X POST 'https://dev.xuqinmin.com/api/im/admin/friend-requests/req_001/accept?appId=ak_demo_chat'
curl -X POST 'https://dev.xuqinmin.com/api/im/admin/blacklist?appId=ak_demo_chat' \
-H 'Content-Type: application/json' \
-d '{"userId":"user_001","blockedUserId":"user_002"}'
curl 'https://dev.xuqinmin.com/api/im/admin/groups/group_001/members?appId=ak_demo_chat'
curl 'https://dev.xuqinmin.com/api/im/admin/groups/group_001/join-requests?appId=ak_demo_chat'
curl -X POST 'https://dev.xuqinmin.com/api/im/admin/groups/group_001/join-requests/req_001/accept?appId=ak_demo_chat'
curl 'https://dev.xuqinmin.com/api/im/admin/keyword-filters?appId=ak_demo_chat'
curl 'https://dev.xuqinmin.com/api/im/admin/global-mute?appId=ak_demo_chat'
IM Webhook 回调
IM 服务会在消息、好友和已读等事件发生后,以 POST 方式向你配置的回调地址推送事件。
请求头:
Content-Type: application/jsonX-App-Id: 应用appIdX-App-Timestamp: 请求时间戳X-App-Nonce: 随机串X-App-Signature: 签名结果
签名规则:
HMAC-SHA256(appSecret, appId + "\n" + timestamp + "\n" + nonce + "\n" + sha256(body))
统一请求体结构:
{
"callbackId": "uuid",
"callbackType": "message",
"callbackEvent": "message.sent",
"requestTime": 1714360000000,
"payload": {},
"signature": null,
"appId": "ak_demo_chat"
}
字段说明:
| 字段 | 说明 |
|---|---|
callbackId |
回调唯一 ID,用于去重和排障 |
callbackType |
回调大类,例如 message、friend、group、blacklist |
callbackEvent |
具体事件,例如 message.sent、friend.request.sent |
requestTime |
毫秒时间戳 |
payload |
事件数据,结构随事件变化 |
signature |
预留字段,当前由请求头承载 |
appId |
回调所属应用 ID |
payload 会根据事件类型变化:
| 事件 | payload 类型 | 说明 |
|---|---|---|
message.sent |
ImMessageEntity |
发送消息成功后触发 |
message.revoked |
ImMessageEntity |
撤回消息后触发 |
message.edited |
ImMessageEntity |
编辑文本消息后触发 |
message.read |
MessageReadCallbackPayload |
已读回执同步后触发 |
friend.request.sent |
FriendRequestCallbackPayload |
好友申请创建后触发 |
friend.request.accepted |
FriendRequestCallbackPayload |
好友申请通过后触发 |
friend.request.rejected |
FriendRequestCallbackPayload |
好友申请拒绝后触发 |
group.join.request.sent |
GroupJoinRequestCallbackPayload |
入群申请创建后触发 |
group.join.request.accepted |
GroupJoinRequestCallbackPayload |
入群申请通过后触发 |
group.join.request.rejected |
GroupJoinRequestCallbackPayload |
入群申请拒绝后触发 |
blacklist.added |
BlacklistCallbackPayload |
黑名单记录新增后触发 |
blacklist.removed |
BlacklistCallbackPayload |
黑名单记录移除后触发 |
各 payload 字段如下:
MessageReadCallbackPayload
{
"appId": "ak_demo_chat",
"readerId": "user_001",
"peerId": "user_002",
"groupId": null,
"chatType": "SINGLE",
"readAt": 1714360000000,
"messageIds": ["msg_001", "msg_002"]
}
FriendRequestCallbackPayload
{
"appId": "ak_demo_chat",
"requestId": "req_001",
"fromUserId": "user_001",
"toUserId": "user_002",
"remark": "hi",
"status": "PENDING",
"reviewedAt": null
}
GroupJoinRequestCallbackPayload
{
"appId": "ak_demo_chat",
"requestId": "req_001",
"groupId": "group_001",
"groupName": "技术群",
"requesterId": "user_003",
"remark": "申请加入",
"status": "PENDING",
"reviewedAt": null
}
BlacklistCallbackPayload
{
"appId": "ak_demo_chat",
"id": "blk_001",
"userId": "user_001",
"blockedUserId": "user_002",
"action": "ADD",
"createdAt": 1714360000000
}
说明:
- 回调发送失败不会影响主流程,只记录日志。
- 当前版本的回调配置是按应用维度管理的,多个地址会同时接收同一事件。
- 新增的好友、入群、黑名单回调都复用同一 envelope 和签名规则,payload 字段按上表中的类型序列化。
- 接收方建议用
callbackId做幂等去重,避免重复投递造成重复处理。 - 服务端当前不做重试队列,失败只会在调用端记录日志。
示例验签:
import crypto from 'crypto'
export function verifyWebhook({
appId,
timestamp,
nonce,
body,
signature,
appSecret,
}: {
appId: string
timestamp: string
nonce: string
body: string
signature: string
appSecret: string
}) {
const bodyHash = crypto.createHash('sha256').update(body, 'utf8').digest('hex')
const payload = `${appId}\n${timestamp}\n${nonce}\n${bodyHash}`
const expected = crypto.createHmac('sha256', appSecret).update(payload, 'utf8').digest('hex')
return expected === signature
}
好友申请 / 黑名单
curl -X POST 'https://dev.xuqinmin.com/api/im/friend-requests?appId=ak_demo_chat&toUserId=user_002&remark=hi'
curl -X POST 'https://dev.xuqinmin.com/api/im/friend-requests/req_001/accept?appId=ak_demo_chat'
curl -X POST 'https://dev.xuqinmin.com/api/im/friend-requests/req_001/reject?appId=ak_demo_chat'
curl 'https://dev.xuqinmin.com/api/im/groups/group_001/join-requests?appId=ak_demo_chat'
curl -X POST 'https://dev.xuqinmin.com/api/im/groups/group_001/join-requests?appId=ak_demo_chat&remark=申请加入'
curl -X POST 'https://dev.xuqinmin.com/api/im/groups/group_001/join-requests/req_001/accept?appId=ak_demo_chat'
curl -X POST 'https://dev.xuqinmin.com/api/im/groups/group_001/join-requests/req_001/reject?appId=ak_demo_chat'
curl -X POST 'https://dev.xuqinmin.com/api/im/blacklist?appId=ak_demo_chat&blockedUserId=user_002'
curl -X DELETE 'https://dev.xuqinmin.com/api/im/blacklist?appId=ak_demo_chat&blockedUserId=user_002'
IM 历史过滤查询
curl 'https://dev.xuqinmin.com/api/im/messages/history/user_002?appId=ak_demo_chat&page=0&size=20&keyword=hello&msgType=TEXT'
curl 'https://dev.xuqinmin.com/api/im/messages/group-history/group_001?appId=ak_demo_chat&page=0&size=20&keyword=user_002&startTime=2026-04-27T00:00:00&endTime=2026-04-27T23:59:59'
支持的筛选参数:keyword、msgType、startTime、endTime。
IM 媒体消息
curl -X POST 'https://file.dev.xuqinmin.com/api/file/upload' \
-H 'Authorization: Bearer <im_jwt>' \
-F 'file=@image.jpg'
curl -X POST 'https://im.dev.xuqinmin.com/api/im/messages/send?appId=ak_demo_chat' \
-H 'Authorization: Bearer <im_jwt>' \
-H 'Content-Type: application/json' \
-d '{"toId":"user_002","chatType":"SINGLE","msgType":"IMAGE","content":"{\"url\":\"https://file.dev.xuqinmin.com/api/file/abc\"}"}'
当前 im-service 的消息发送接口已经支持 AUDIO、LOCATION、CUSTOM、RICH_TEXT、FORWARD、QUOTE、MERGE、CALL_AUDIO、CALL_VIDEO 这些通用类型,客户端只需按协议传入对应 JSON 内容即可。
群聊消息在历史查询和实时推送里会携带 groupReadCount,用于展示 N 人已读。