529 lines
13 KiB
Markdown
529 lines
13 KiB
Markdown
# 用户装扮 Flutter 对接文档
|
||
|
||
## 通用说明
|
||
|
||
所有需要登录的接口都需要带:
|
||
|
||
```http
|
||
Authorization: Bearer <token>
|
||
```
|
||
|
||
统一返回外壳:
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "OK",
|
||
"request_id": "xxx",
|
||
"data": {}
|
||
}
|
||
```
|
||
|
||
下文只描述 `data` 内部字段。
|
||
|
||
## 1. 获取我的装扮聚合
|
||
|
||
地址:
|
||
|
||
```http
|
||
GET /api/v1/appearance
|
||
GET /api/v1/users/me/appearance
|
||
```
|
||
|
||
参数:无。
|
||
|
||
返回值:
|
||
|
||
```json
|
||
{
|
||
"user_id": "42",
|
||
"avatar_frame": {
|
||
"resource_id": 8101,
|
||
"resource_code": "frame_gold",
|
||
"resource_type": "avatar_frame",
|
||
"name": "Gold Frame",
|
||
"asset_url": "https://cdn.example/frame.png",
|
||
"preview_url": "",
|
||
"animation_url": "https://cdn.example/frame.svga",
|
||
"metadata_json": "{}",
|
||
"entitlement_id": "ent-frame",
|
||
"expires_at_ms": 1999999999999
|
||
},
|
||
"profile_card": {},
|
||
"vehicle": {
|
||
"resource_id": 8102,
|
||
"resource_code": "vehicle_gold",
|
||
"resource_type": "vehicle",
|
||
"name": "Gold Vehicle",
|
||
"asset_url": "https://cdn.example/vehicle.png",
|
||
"preview_url": "",
|
||
"animation_url": "https://cdn.example/vehicle.svga",
|
||
"metadata_json": "{}",
|
||
"entitlement_id": "ent-vehicle",
|
||
"expires_at_ms": 1999999999999
|
||
},
|
||
"mic_seat_animation": {
|
||
"resource_id": 8106,
|
||
"resource_code": "mic_seat_wave_gold",
|
||
"resource_type": "mic_seat_animation",
|
||
"name": "Gold Mic Wave",
|
||
"asset_url": "https://cdn.example/mic-seat.png",
|
||
"preview_url": "",
|
||
"animation_url": "https://cdn.example/mic-seat.svga",
|
||
"metadata_json": "{}",
|
||
"entitlement_id": "ent-mic-seat-wave",
|
||
"expires_at_ms": 1999999999999
|
||
},
|
||
"equipped_badges": [],
|
||
"badges": [
|
||
{
|
||
"slot": "strip",
|
||
"position": 1,
|
||
"badge_form": "icon",
|
||
"resource_id": 8103,
|
||
"resource": {
|
||
"resource_id": 8103,
|
||
"resource_code": "badge_host",
|
||
"resource_type": "badge",
|
||
"name": "Host Badge",
|
||
"asset_url": "https://cdn.example/badge.png",
|
||
"preview_url": "",
|
||
"animation_url": "",
|
||
"metadata_json": "{}",
|
||
"entitlement_id": "",
|
||
"expires_at_ms": 0
|
||
},
|
||
"entitlement_id": "ent-badge",
|
||
"source_type": "achievement",
|
||
"source_id": "ach-host",
|
||
"pin_mode": "auto",
|
||
"updated_at_ms": 1778256000000
|
||
}
|
||
],
|
||
"badge_profile": {
|
||
"strip_badges": [],
|
||
"profile_tile_badges": [],
|
||
"honor_badges": [],
|
||
"server_time_ms": 1778256000000
|
||
},
|
||
"resources": [
|
||
{
|
||
"resource_id": 8106,
|
||
"resource_code": "mic_seat_wave_gold",
|
||
"resource_type": "mic_seat_animation",
|
||
"name": "Gold Mic Wave",
|
||
"asset_url": "https://cdn.example/mic-seat.png",
|
||
"preview_url": "",
|
||
"animation_url": "https://cdn.example/mic-seat.svga",
|
||
"metadata_json": "{}",
|
||
"entitlement_id": "ent-mic-seat-wave",
|
||
"expires_at_ms": 1999999999999
|
||
}
|
||
],
|
||
"server_time_ms": 1778256000000
|
||
}
|
||
```
|
||
|
||
字段说明:
|
||
|
||
| 字段 | 说明 |
|
||
|---|---|
|
||
| user_id | 用户 ID,字符串 |
|
||
| avatar_frame | 当前佩戴头像框,未佩戴时为 `{}` |
|
||
| profile_card | 当前佩戴背景卡,未佩戴时为 `{}` |
|
||
| vehicle | 当前佩戴入场座驾,未佩戴时为 `{}` |
|
||
| mic_seat_animation | 当前佩戴麦位声波,未佩戴时为 `{}` |
|
||
| equipped_badges | wallet 当前佩戴的 badge 权益 |
|
||
| badges | 房间、公屏等高频展示用徽章,取 `strip_badges` |
|
||
| badge_profile | 完整徽章展示配置 |
|
||
| resources | 当前佩戴资源的完整列表 |
|
||
| server_time_ms | 服务端时间戳 |
|
||
|
||
说明:
|
||
|
||
- 过期佩戴不会返回。
|
||
- 头像框、背景卡、入场座驾、麦位声波来自 wallet 当前佩戴。
|
||
- 徽章展示配置来自 activity。
|
||
- 客户端渲染动画优先使用 `animation_url`,没有动画时用 `asset_url` 或 `preview_url` 兜底。
|
||
|
||
## 2. 获取我的资源背包
|
||
|
||
地址:
|
||
|
||
```http
|
||
GET /api/v1/users/me/resources
|
||
```
|
||
|
||
参数:
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|---|---|---|---|
|
||
| resource_type | string | 否 | `avatar_frame` / `profile_card` / `vehicle` / `badge` / `chat_bubble` |
|
||
|
||
示例:
|
||
|
||
```http
|
||
GET /api/v1/users/me/resources?resource_type=vehicle
|
||
```
|
||
|
||
返回值:
|
||
|
||
```json
|
||
{
|
||
"items": [
|
||
{
|
||
"entitlement_id": "ent-vehicle",
|
||
"resource_id": 8102,
|
||
"resource": {
|
||
"resource_id": 8102,
|
||
"resource_code": "vehicle_gold",
|
||
"resource_type": "vehicle",
|
||
"name": "Gold Vehicle",
|
||
"status": "active",
|
||
"usage_scopes": ["room_entry"],
|
||
"asset_url": "https://cdn.example/vehicle.png",
|
||
"preview_url": "",
|
||
"animation_url": "https://cdn.example/vehicle.svga",
|
||
"metadata_json": "{}"
|
||
},
|
||
"status": "active",
|
||
"quantity": 1,
|
||
"remaining_quantity": 1,
|
||
"effective_at_ms": 1778256000000,
|
||
"expires_at_ms": 1999999999999,
|
||
"source_grant_id": "grant-1",
|
||
"created_at_ms": 1778256000000,
|
||
"updated_at_ms": 1778256000000,
|
||
"equipped": true
|
||
}
|
||
],
|
||
"total": 1
|
||
}
|
||
```
|
||
|
||
字段说明:
|
||
|
||
| 字段 | 说明 |
|
||
|---|---|
|
||
| entitlement_id | 用户权益 ID,佩戴时建议传这个值 |
|
||
| resource_id | 资源 ID |
|
||
| resource | 资源素材和基础信息 |
|
||
| status | 权益状态 |
|
||
| quantity | 总数量 |
|
||
| remaining_quantity | 剩余数量 |
|
||
| effective_at_ms | 生效时间 |
|
||
| expires_at_ms | 过期时间,0 表示不过期 |
|
||
| equipped | 是否当前佩戴 |
|
||
|
||
## 3. 佩戴资源
|
||
|
||
地址:
|
||
|
||
```http
|
||
POST /api/v1/users/me/resources/{resource_id}/equip
|
||
```
|
||
|
||
路径参数:
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|---|---|---|---|
|
||
| resource_id | int64 | 是 | 资源 ID |
|
||
|
||
Body:
|
||
|
||
```json
|
||
{
|
||
"entitlement_id": "ent-vehicle"
|
||
}
|
||
```
|
||
|
||
Body 参数:
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|---|---|---|---|
|
||
| entitlement_id | string | 否 | 用户权益 ID,建议传 |
|
||
|
||
返回值:
|
||
|
||
```json
|
||
{
|
||
"entitlement_id": "ent-vehicle",
|
||
"resource_id": 8102,
|
||
"resource": {},
|
||
"status": "active",
|
||
"quantity": 1,
|
||
"remaining_quantity": 1,
|
||
"effective_at_ms": 1778256000000,
|
||
"expires_at_ms": 1999999999999,
|
||
"equipped": true
|
||
}
|
||
```
|
||
|
||
说明:
|
||
|
||
- 可佩戴类型:`avatar_frame`、`profile_card`、`vehicle`、`chat_bubble`、`badge`、`mic_seat_animation`。
|
||
- `badge`、`mic_seat_animation` 发放成功后服务端默认佩戴。
|
||
- 过期资源不能佩戴。
|
||
- 不传 `entitlement_id` 时,服务端会选择当前有效权益。
|
||
|
||
## 4. 取消佩戴
|
||
|
||
地址:
|
||
|
||
```http
|
||
DELETE /api/v1/users/me/resources/{resource_type}/unequip
|
||
```
|
||
|
||
路径参数:
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|---|---|---|---|
|
||
| resource_type | string | 是 | `avatar_frame` / `profile_card` / `vehicle` / `chat_bubble` / `badge` |
|
||
|
||
返回值:
|
||
|
||
```json
|
||
{
|
||
"resource_type": "vehicle",
|
||
"unequipped": true,
|
||
"updated_at_ms": 1778256000000
|
||
}
|
||
```
|
||
|
||
说明:
|
||
|
||
- 重复取消不会报错。
|
||
- 用户本来没佩戴该类型时,`unequipped=false`。
|
||
|
||
## 5. 批量获取房间展示资料
|
||
|
||
地址:
|
||
|
||
```http
|
||
GET /api/v1/users/room-display-profiles:batch
|
||
```
|
||
|
||
参数:
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|---|---|---|---|
|
||
| user_ids | string | 是 | 多个用户 ID,逗号分隔 |
|
||
| user_id | string | 否 | 也支持重复传多个 `user_id` |
|
||
|
||
示例:
|
||
|
||
```http
|
||
GET /api/v1/users/room-display-profiles:batch?user_ids=42,43
|
||
```
|
||
|
||
返回值:
|
||
|
||
```json
|
||
{
|
||
"profiles": [
|
||
{
|
||
"user_id": "42",
|
||
"username": "Tom",
|
||
"avatar": "https://cdn.example/avatar.png",
|
||
"display_user_id": "100001",
|
||
"gender": "male",
|
||
"age": 22,
|
||
"country": "CN",
|
||
"country_name": "China",
|
||
"country_display_name": "China",
|
||
"country_flag": "CN",
|
||
"vip": {},
|
||
"level": {},
|
||
"badges": [],
|
||
"avatar_frame": {
|
||
"resource_id": 8101,
|
||
"resource_code": "frame_gold",
|
||
"resource_type": "avatar_frame",
|
||
"name": "Gold Frame",
|
||
"asset_url": "https://cdn.example/frame.png",
|
||
"preview_url": "",
|
||
"animation_url": "https://cdn.example/frame.svga",
|
||
"metadata_json": "{}",
|
||
"entitlement_id": "ent-frame",
|
||
"expires_at_ms": 1999999999999
|
||
},
|
||
"profile_card": {
|
||
"resource_id": 8104,
|
||
"resource_code": "profile_card_gold",
|
||
"resource_type": "profile_card",
|
||
"name": "Gold Profile Card",
|
||
"asset_url": "https://cdn.example/profile-card.png",
|
||
"preview_url": "",
|
||
"animation_url": "https://cdn.example/profile-card.mp4",
|
||
"metadata_json": "{\"profile_card_layout\":{\"source_width\":1136,\"source_height\":1680,\"content_top\":143,\"content_height\":1525}}",
|
||
"entitlement_id": "ent-profile-card",
|
||
"expires_at_ms": 1999999999999
|
||
},
|
||
"vehicle": {
|
||
"resource_id": 8102,
|
||
"resource_code": "vehicle_gold",
|
||
"resource_type": "vehicle",
|
||
"name": "Gold Vehicle",
|
||
"asset_url": "https://cdn.example/vehicle.png",
|
||
"preview_url": "",
|
||
"animation_url": "https://cdn.example/vehicle.svga",
|
||
"metadata_json": "{}",
|
||
"entitlement_id": "ent-vehicle",
|
||
"expires_at_ms": 1999999999999
|
||
},
|
||
"mic_seat_animation": {
|
||
"resource_id": 8106,
|
||
"resource_code": "mic_seat_wave_gold",
|
||
"resource_type": "mic_seat_animation",
|
||
"name": "Gold Mic Wave",
|
||
"asset_url": "https://cdn.example/mic-seat.png",
|
||
"preview_url": "",
|
||
"animation_url": "https://cdn.example/mic-seat.svga",
|
||
"metadata_json": "{}",
|
||
"entitlement_id": "ent-mic-seat-wave",
|
||
"expires_at_ms": 1999999999999
|
||
},
|
||
"charm": 0
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
说明:
|
||
|
||
- 房间、公屏、在线列表展示头像框用 `avatar_frame`。
|
||
- 房间资料卡展示用 `profile_card`,从 `metadata_json.profile_card_layout` 解析 `content_top` 和 `content_height`。
|
||
- 入场座驾展示用 `vehicle`。
|
||
- 麦位声波展示用 `mic_seat_animation`。
|
||
- 徽章条展示用 `badges`。
|
||
- 过期佩戴不会返回。
|
||
|
||
## 6. 进房
|
||
|
||
地址:
|
||
|
||
```http
|
||
POST /api/v1/rooms/join
|
||
```
|
||
|
||
Body:
|
||
|
||
```json
|
||
{
|
||
"room_id": "room_1001",
|
||
"command_id": "cmd-join-1001",
|
||
"role": "audience",
|
||
"password": "1234"
|
||
}
|
||
```
|
||
|
||
参数:
|
||
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|---|---|---|---|
|
||
| room_id | string | 是 | 房间 ID |
|
||
| command_id | string | 是 | 幂等 ID,Flutter 每次进房动作生成一个 |
|
||
| role | string | 否 | 默认 `audience` |
|
||
| password | string | 否 | 锁房密码 |
|
||
|
||
返回值:
|
||
|
||
```json
|
||
{
|
||
"result": {
|
||
"applied": true,
|
||
"room_version": 9,
|
||
"server_time_ms": 1778256000000
|
||
},
|
||
"room": {},
|
||
"viewer": {},
|
||
"seats": [],
|
||
"contribution_rank": [],
|
||
"profiles": [
|
||
{
|
||
"user_id": "42",
|
||
"display_user_id": "100001",
|
||
"username": "Tom",
|
||
"avatar": "https://cdn.example/avatar.png"
|
||
}
|
||
],
|
||
"im": {
|
||
"group_id": "room_1001",
|
||
"need_join_group": true
|
||
},
|
||
"rtc": {
|
||
"need_token": true,
|
||
"available": true,
|
||
"token": {}
|
||
},
|
||
"server_time_ms": 1778256000000
|
||
}
|
||
```
|
||
|
||
说明:
|
||
|
||
- Flutter 不需要传入场座驾。
|
||
- 服务端会在进房时自动读取当前佩戴的 `vehicle`,写入房间 IM。
|
||
- `join` 返回里的 `profiles` 是基础资料。
|
||
- 房间增强资料用 `/users/room-display-profiles:batch`,或使用房间详情、在线用户列表里内嵌的 `profile` 字段。
|
||
|
||
## 7. 相关 IM
|
||
|
||
### 用户进房
|
||
|
||
腾讯 IM 群自定义消息:
|
||
|
||
```json
|
||
{
|
||
"event_id": "evt_xxx",
|
||
"room_id": "room_1001",
|
||
"event_type": "room_user_joined",
|
||
"actor_user_id": 42,
|
||
"target_user_id": 42,
|
||
"room_version": 9,
|
||
"entry_vehicle": {
|
||
"resource_id": 8102,
|
||
"resource_code": "vehicle_gold",
|
||
"name": "Gold Vehicle",
|
||
"asset_url": "https://cdn.example/vehicle.png",
|
||
"preview_url": "",
|
||
"animation_url": "https://cdn.example/vehicle.svga",
|
||
"metadata_json": "{}",
|
||
"entitlement_id": "ent-vehicle",
|
||
"expires_at_ms": 1999999999999
|
||
},
|
||
"attributes": {
|
||
"role": "audience"
|
||
}
|
||
}
|
||
```
|
||
|
||
Flutter 处理:
|
||
|
||
| 字段 | 说明 |
|
||
|---|---|
|
||
| event_type | `room_user_joined` 表示用户进入房间 |
|
||
| actor_user_id | 进房用户 ID |
|
||
| target_user_id | 进房用户 ID |
|
||
| room_version | 房间版本 |
|
||
| entry_vehicle | 入场座驾快照 |
|
||
| attributes.role | 用户进房角色,仅用于展示 |
|
||
|
||
处理规则:
|
||
|
||
- `entry_vehicle.resource_id > 0`:播放入场座驾。
|
||
- `entry_vehicle.animation_url`:优先用于动画播放。
|
||
- `entry_vehicle.asset_url` / `entry_vehicle.preview_url`:动画不可用时兜底展示。
|
||
- `entry_vehicle` 不存在或为空:普通进房,不播放座驾。
|
||
- 不要收到进房 IM 后再实时请求 `/appearance` 查询座驾,直接使用 IM 中的 `entry_vehicle` 快照。
|
||
|
||
## 8. Flutter 调用建议
|
||
|
||
1. 个人装扮页进入时调 `/api/v1/appearance`。
|
||
2. 背包页调 `/api/v1/users/me/resources?resource_type=xxx`。
|
||
3. 点击佩戴调 `POST /api/v1/users/me/resources/{resource_id}/equip`,成功后刷新 `/appearance`。
|
||
4. 点击取消佩戴调 `DELETE /api/v1/users/me/resources/{resource_type}/unequip`,成功后刷新 `/appearance`。
|
||
5. 个人主页信息卡背景使用个人资料返回的 `profile_bg_img`;该字段是用户资料字段,和 `profile_card` 装扮资源无关。
|
||
6. 房间、公屏、在线用户资料优先使用 `room-display-profiles:batch` 的 `avatar_frame`、`profile_card`、`vehicle`、`badges`。
|
||
7. 收到 `room_user_joined` IM 时,只按 `entry_vehicle` 播放入场座驾。
|