From a5988b34203e8254f276241a6e660121a168e5a7 Mon Sep 17 00:00:00 2001 From: Jolie <412895109@qq.com> Date: Thu, 15 Jan 2026 16:58:08 +0800 Subject: [PATCH] =?UTF-8?q?docs(system):=20=E6=B7=BB=E5=8A=A0=E6=A0=B8?= =?UTF-8?q?=E5=BF=83=E7=BB=84=E4=BB=B6=E4=BA=A4=E6=8E=A5=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 详细说明 RoomController 直播房间控制器功能和使用方法 - 详细介绍 IMManager 即时通讯管理器的初始化和消息处理流程 - 完整描述 RTCManager 实时音视频管理器的音视频流管理功能 - 详述 RTMManager 实时消息管理器的频道订阅和消息发布机制 - 说明 ChatController 一对一聊天控制器的消息管理和用户状态功能 - 提供各组件间的依赖关系图和交互流程说明 - 包含使用示例和注意事项以指导后续开发维护工作 --- 核心组件交接文档.md | 1090 +++++++++++++++++++++++++++++++++++ 1 file changed, 1090 insertions(+) create mode 100644 核心组件交接文档.md diff --git a/核心组件交接文档.md b/核心组件交接文档.md new file mode 100644 index 0000000..9cb69e0 --- /dev/null +++ b/核心组件交接文档.md @@ -0,0 +1,1090 @@ +# 核心组件交接文档 + +本文档详细说明了项目中5个核心控制器/管理器的功能、使用方法和注意事项。 + +## 目录 + +- [RoomController - 直播房间控制器](#roomcontroller---直播房间控制器) +- [IMManager - 即时通讯管理器](#immanager---即时通讯管理器) +- [RTCManager - 实时音视频管理器](#rtcmanager---实时音视频管理器) +- [RTMManager - 实时消息管理器](#rtmmanager---实时消息管理器) +- [ChatController - 聊天控制器](#chatcontroller---聊天控制器) + +--- + +## RoomController - 直播房间控制器 + +### 文件位置 +`lib/controller/discover/room_controller.dart` + +### 功能概述 +负责管理直播房间相关的所有功能,包括: +- 创建/加入直播频道 +- 管理直播角色(主持人、男嘉宾、女嘉宾、观众) +- 处理直播间聊天消息 +- 管理礼物赠送 +- 管理连麦功能 +- 管理玫瑰余额 + +### 核心属性 + +```dart +// 当前角色 +CurrentRole currentRole = CurrentRole.normalUser; + +// 是否正在直播 +var isLive = false.obs; + +// 当前频道信息 +final Rxn rtcChannel = Rxn(); +final Rxn rtcChannelDetail = Rxn(); + +// 聊天消息列表 +final RxList chatMessages = [].obs; + +// 礼物产品列表 +final RxList giftProducts = [].obs; + +// 玫瑰数量 +final RxInt roseCount = 0.obs; +``` + +### 主要方法 + +#### 1. 创建直播频道 +```dart +Future createRtcChannel() async +``` +- **功能**: 创建新的直播频道,主持人角色 +- **前置条件**: + - 不能正在直播中 + - 不能正在通话中(会检查 CallController) + - 需要摄像头和麦克风权限 +- **流程**: + 1. 检查权限 + 2. 调用 API 创建频道 + 3. 设置角色为 broadcaster + 4. 加入 RTC 频道 + 5. 跳转到直播页面 + +#### 2. 加入直播频道 +```dart +Future joinChannel(String channelName) async +``` +- **功能**: 作为观众加入他人的直播频道 +- **参数**: `channelName` - 频道ID +- **前置条件**: 不能正在通话中 + +#### 3. 上麦(加入聊天) +```dart +Future joinChat(CurrentRole role) async +``` +- **功能**: 上麦参与直播聊天 +- **参数**: `role` - 角色类型(男嘉宾/女嘉宾/普通观众) +- **权限要求**: + - 男/女嘉宾:需要摄像头和麦克风权限 + - 普通观众:只需要麦克风权限 +- **流程**: + 1. 检查权限 + 2. 调用连接 RTC 频道接口 + 3. 根据角色发布音视频流 + 4. 刷新连麦卡片数据 + +#### 4. 下麦(离开聊天) +```dart +Future leaveChat() async +``` +- **功能**: 下麦,停止发布音视频流 +- **流程**: + 1. 调用断开 RTC 频道连接接口 + 2. 停止发布音视频 + 3. 更新频道详情(清空对应角色信息) + +#### 5. 离开频道 +```dart +Future leaveChannel() async +``` +- **功能**: 完全离开直播频道 +- **流程**: + - 如果是主持人:销毁频道并发送结束直播消息 + - 如果是嘉宾:断开连接 + - 清理所有状态 + +#### 6. 发送礼物 +```dart +Future sendGift({ + required GiftProductModel gift, + required int targetUserId, + required int type, +}) async +``` +- **功能**: 在直播间赠送礼物 +- **参数**: + - `gift`: 礼物产品模型 + - `targetUserId`: 目标用户ID + - `type`: 类型(1=送礼,2=添加好友) +- **流程**: + 1. 调用消费接口 + 2. 检查玫瑰余额(不足时弹出充值弹框) + 3. 刷新玫瑰数量 + 4. 添加到 SVGA 动画播放队列 + 5. 发送 RTM 消息通知其他用户 + 6. 在公屏显示礼物消息 + +#### 7. 发送公屏消息 +```dart +Future sendChatMessage(String content) async +``` +- **功能**: 在直播间发送文字消息到公屏 + +#### 8. 获取虚拟账户(玫瑰余额) +```dart +Future getVirtualAccount() async +``` +- **功能**: 刷新用户的玫瑰余额 +- **使用场景**: 充值成功后、消费后需要刷新余额时调用 + +#### 9. 获取频道详情 +```dart +Future fetchRtcChannelDetail(String channelName) async +``` +- **功能**: 获取直播频道的详细信息(主持人、嘉宾信息等) + +### 使用示例 + +```dart +// 获取 RoomController 实例 +final roomController = Get.find(); + +// 创建直播频道 +await roomController.createRtcChannel(); + +// 监听消息列表 +Obx(() => ListView.builder( + itemCount: roomController.chatMessages.length, + itemBuilder: (context, index) { + final message = roomController.chatMessages[index]; + return Text(message.content); + }, +)); + +// 发送礼物 +await roomController.sendGift( + gift: giftProduct, + targetUserId: targetUserId, + type: 1, +); +``` + +### 注意事项 + +1. **生命周期管理**: + - 在 `onInit()` 中注册消息监听和加载礼物列表 + - 在 `onClose()` 中移除监听和清空消息列表 + +2. **权限检查**: + - 创建频道和上麦前都会检查权限 + - 权限被拒绝时会提示用户去设置中开启 + +3. **状态同步**: + - 使用响应式变量(`.obs`)管理状态 + - UI 通过 `Obx` 或 `GetBuilder` 监听状态变化 + +4. **消息去重**: + - 消息列表会自动去重(基于 userId + content + timestamp) + - 最多保留 300 条消息 + +5. **与 CallController 的互斥**: + - 创建/加入频道前会检查是否正在通话 + - 确保直播和通话不会同时进行 + +--- + +## IMManager - 即时通讯管理器 + +### 文件位置 +`lib/im/im_manager.dart` + +### 功能概述 +负责管理环信 IM SDK 的初始化和消息处理,包括: +- IM SDK 初始化和登录 +- 消息接收和分发 +- 通话消息处理 +- 用户在线状态管理 +- 消息通知管理 +- ChatController 注册管理 + +### 核心属性 + +```dart +// 初始化状态 +bool _initialized = false; +bool _loggedIn = false; + +// 活跃的 ChatController 实例 +final Map _activeChatControllers = {}; + +// Presence 状态变化回调 +final Map _presenceCallbacks = {}; + +// 消息通知队列 +final List<_NotificationMessage> _notificationQueue = []; +``` + +### 主要方法 + +#### 1. 初始化 IM +```dart +Future ensureInitialized({required String appKey}) async +``` +- **功能**: 初始化环信 IM SDK +- **参数**: `appKey` - 环信 AppKey(格式:orgname#appname) +- **特点**: + - 支持并发调用,只初始化一次 + - 使用 Completer 确保并发安全 +- **流程**: + 1. 创建 EMOptions + 2. 调用 SDK 初始化 + 3. 注册监听器 + 4. 初始化本地通知服务 + +#### 2. 登录 +```dart +Future login({ + required String userId, + required String token, +}) async +``` +- **功能**: 使用用户ID和Token登录环信 +- **参数**: + - `userId`: 用户ID + - `token`: 环信Token(从服务器获取) +- **返回**: 登录是否成功 + +#### 3. 登出 +```dart +Future logout() async +``` +- **功能**: 登出环信,清理状态 + +#### 4. 注册 ChatController +```dart +void registerChatController(ChatController controller) +``` +- **功能**: 注册 ChatController,用于接收该用户的消息 +- **使用场景**: ChatController 初始化时调用 + +#### 5. 注销 ChatController +```dart +void unregisterChatController(String userId) +``` +- **功能**: 注销 ChatController +- **使用场景**: ChatController 销毁时调用 + +#### 6. 获取用户信息 +```dart +Future getUserInfo(String userId) async +``` +- **功能**: 从环信服务器获取用户信息 + +#### 7. 发送消息 +```dart +Future sendMessage({ + required String toUserId, + required String content, + MessageType type = MessageType.TXT, +}) async +``` +- **功能**: 发送文本消息 +- **注意**: 实际发送消息通常通过 ChatController,这个方法主要用于特殊场景 + +### 消息处理流程 + +#### 消息接收流程 +1. **消息监听器接收**: `onMessagesReceived` 回调 +2. **消息分发**: + - 查找对应的 ChatController + - 如果找到,添加到对应 Controller 的消息列表 + - 如果未找到,显示通知弹框 +3. **通话消息特殊处理**: + - 检测通话消息(event == 'call') + - 显示视频通话邀请弹框 + - 播放来电铃声 +4. **消息状态更新**: + - 监听 `onMessageContentChanged` + - 处理通话状态变化(calling、rejected、cancelled等) + +#### 通话消息处理 +- **接收方**: + - 显示 `VideoCallInviteDialog` 弹框 + - 播放来电铃声 + - 点击弹框跳转到 `VideoCallPage`(`isInitiator: false`) +- **状态更新**: + - 监听消息内容变化 + - 通知 `CallController` 处理状态变化 + +### 使用示例 + +```dart +// 初始化 IM +await IMManager.instance.ensureInitialized( + appKey: 'your_app_key', +); + +// 登录 +final success = await IMManager.instance.login( + userId: 'user123', + token: 'hx_token', +); + +// 获取用户信息 +final userInfo = await IMManager.instance.getUserInfo('user123'); + +// 注册 ChatController(在 ChatController.onInit 中) +IMManager.instance.registerChatController(this); + +// 注销 ChatController(在 ChatController.onClose 中) +IMManager.instance.unregisterChatController(userId); +``` + +### 注意事项 + +1. **初始化时机**: + - 在应用启动时初始化(`main.dart` 或 `MyApp` 的 `initState`) + - 确保只初始化一次 + +2. **登录时机**: + - 用户登录成功后调用 + - Token 从服务器获取 + +3. **消息分发**: + - 消息会自动分发到对应的 ChatController + - 如果没有对应的 ChatController,会显示通知 + +4. **通话消息**: + - 通话消息会触发特殊的 UI 处理(弹框、铃声) + - 需要确保 CallController 已初始化 + +5. **连接状态**: + - 监听连接状态变化 + - 断开连接时会自动重连 + - 被其他设备踢下线时会处理登出逻辑 + +6. **线程安全**: + - 使用 Completer 确保并发初始化安全 + - 消息处理使用 `Future.microtask` 确保在主线程执行 + +--- + +## RTCManager - 实时音视频管理器 + +### 文件位置 +`lib/rtc/rtc_manager.dart` + +### 功能概述 +负责管理声网 Agora RTC SDK,提供音视频通话和直播功能: +- RTC Engine 初始化 +- 加入/离开频道 +- 音视频流管理(发布/订阅) +- 远端用户管理 +- 事件回调处理 + +### 核心属性 + +```dart +// RTC Engine 实例 +RtcEngine? _engine; + +// 频道状态 +bool _isInChannel = false; +String? _currentChannelId; +int? _currentUid; + +// 客户端角色 +ClientRoleType _clientRole = ClientRoleType.clientRoleBroadcaster; + +// 远端用户列表 +final List _remoteUserIds = []; + +// 状态通知器 +final ValueNotifier channelJoinedNotifier = ValueNotifier(false); +final ValueNotifier> remoteUsersNotifier = ValueNotifier>([]); + +// RTC 类型 +RTCType type = RTCType.live; // live 或 call +``` + +### 主要方法 + +#### 1. 初始化 RTC Engine +```dart +Future initialize({ + required String appId, + ChannelProfileType channelProfile = ChannelProfileType.channelProfileLiveBroadcasting, +}) async +``` +- **功能**: 初始化声网 RTC Engine +- **参数**: + - `appId`: 声网 App ID + - `channelProfile`: 频道场景类型(默认直播模式) +- **流程**: + 1. 创建 RTC Engine + 2. 初始化 Engine + 3. 设置客户端角色 + 4. 配置视频编码 + 5. 启用视频 + 6. 注册事件处理器 + +#### 2. 加入频道 +```dart +Future joinChannel({ + required String token, + required String channelId, + required int uid, + required ClientRoleType role, + required RTCType rtcType, +}) async +``` +- **功能**: 加入 RTC 频道 +- **参数**: + - `token`: RTC Token + - `channelId`: 频道ID + - `uid`: 用户ID + - `role`: 客户端角色(主播/观众) + - `rtcType`: RTC 类型(直播/通话) +- **流程**: + 1. 设置 RTC 类型 + 2. 设置客户端角色 + 3. 加入频道 + 4. 触发 `onJoinChannelSuccess` 回调 + +#### 3. 离开频道 +```dart +Future leaveChannel() async +``` +- **功能**: 离开当前频道 +- **流程**: + 1. 取消订阅所有远端用户 + 2. 离开频道 + 3. 清理状态 + +#### 4. 发布视频 +```dart +Future publishVideo(CurrentRole role) async +``` +- **功能**: 发布本地视频流(用于直播上麦) +- **参数**: `role` - 角色类型 + +#### 5. 发布音频 +```dart +Future publishAudio() async +``` +- **功能**: 发布本地音频流(用于观众上麦) + +#### 6. 停止发布 +```dart +Future unpublish(CurrentRole role) async +``` +- **功能**: 停止发布音视频流(下麦) + +#### 7. 启用/禁用视频 +```dart +Future enableVideo() async +Future disableVideo() async +``` +- **功能**: 控制本地视频的开启/关闭 + +#### 8. 静音/取消静音 +```dart +Future muteLocalAudio(bool muted) async +``` +- **功能**: 控制本地音频的静音状态 + +#### 9. 设置扬声器 +```dart +Future setEnableSpeakerphone(bool enabled) async +``` +- **功能**: 控制扬声器开关 + +### 事件回调 + +#### 频道事件 +- `onJoinChannelSuccess`: 加入频道成功 +- `onLeaveChannel`: 离开频道 +- `onConnectionStateChanged`: 连接状态变化 +- `onConnectionLost`: 连接丢失 + +#### 用户事件 +- `onUserJoined`: 远端用户加入 +- `onUserOffline`: 远端用户离开 +- `onUserMuteAudio`: 用户静音状态变化 +- `onUserMuteVideo`: 用户视频状态变化 +- `onFirstRemoteVideoDecoded`: 首帧远端视频解码完成 +- `onVideoSizeChanged`: 视频尺寸变化 + +### 使用示例 + +```dart +// 初始化 RTC +await RTCManager.instance.initialize( + appId: 'your_app_id', +); + +// 加入频道(直播) +await RTCManager.instance.joinChannel( + token: rtcToken, + channelId: channelId, + uid: uid, + role: ClientRoleType.clientRoleBroadcaster, + rtcType: RTCType.live, +); + +// 监听频道加入状态 +RTCManager.instance.channelJoinedNotifier.addListener(() { + if (RTCManager.instance.channelJoinedNotifier.value) { + print('已加入频道'); + } +}); + +// 监听远端用户 +RTCManager.instance.remoteUsersNotifier.addListener(() { + final remoteUsers = RTCManager.instance.remoteUsersNotifier.value; + print('远端用户数: ${remoteUsers.length}'); +}); + +// 发布视频(上麦) +await RTCManager.instance.publishVideo(CurrentRole.maleAudience); + +// 离开频道 +await RTCManager.instance.leaveChannel(); +``` + +### 注意事项 + +1. **初始化时机**: + - 在应用启动时初始化(`main.dart`) + - 只需要初始化一次 + +2. **RTC 类型**: + - `RTCType.live`: 直播场景 + - `RTCType.call`: 通话场景 + - 类型会影响事件处理逻辑 + +3. **角色管理**: + - `clientRoleBroadcaster`: 主播角色,可以发布音视频 + - `clientRoleAudience`: 观众角色,只能订阅 + +4. **状态通知**: + - 使用 `ValueNotifier` 提供状态通知 + - UI 可以通过监听器响应状态变化 + +5. **与 RoomController 的交互**: + - 加入频道成功后会调用 `RoomController.fetchRtcChannelDetail` + - 只有直播类型才会执行 RoomController 的逻辑 + +6. **与 CallController 的交互**: + - 通话场景下,CallController 会设置 `remoteUid` + - 用于显示远端视频 + +7. **资源清理**: + - 离开频道时会自动清理订阅 + - 应用退出时需要调用 `dispose()` 释放资源 + +--- + +## RTMManager - 实时消息管理器 + +### 文件位置 +`lib/rtc/rtm_manager.dart` + +### 功能概述 +负责管理声网 Agora RTM SDK,提供实时消息功能: +- RTM Client 初始化 +- 频道订阅/取消订阅 +- 频道消息发布 +- 事件监听(消息、Presence、Topic等) + +### 核心属性 + +```dart +// RTM Client 实例 +RtmClient? _client; + +// 初始化状态 +bool _isInitialized = false; +bool _isLoggedIn = false; + +// 当前 AppId 和 UserId +String? _currentAppId; +String? _currentUserId; + +// StreamChannel 映射 +final Map _streamChannels = {}; + +// 事件回调 +void Function(MessageEvent event)? onMessageEvent; +void Function(PresenceEvent event)? onPresenceEvent; +void Function(TopicEvent event)? onTopicEvent; +// ... 其他事件回调 +``` + +### 主要方法 + +#### 1. 初始化 RTM +```dart +Future initialize({ + required String appId, + required String userId, + RtmConfig? config, +}) async +``` +- **功能**: 初始化 RTM Client +- **参数**: + - `appId`: 声网 App ID + - `userId`: 用户ID + - `config`: RTM 配置(可选) +- **流程**: + 1. 创建 RTM Client + 2. 注册客户端监听器 + 3. 获取 RTM Token + 4. 自动登录 + +#### 2. 登录 +```dart +Future login(String token) async +``` +- **功能**: 使用 Token 登录 RTM +- **参数**: `token` - RTM Token(从服务器获取或本地生成) +- **注意**: 初始化时会自动调用登录 + +#### 3. 订阅频道 +```dart +Future subscribe(String channelName) async +``` +- **功能**: 订阅频道,接收频道消息 +- **参数**: `channelName` - 频道名称 +- **使用场景**: 加入直播频道时调用 + +#### 4. 取消订阅 +```dart +Future unsubscribe(String channelName) async +``` +- **功能**: 取消订阅频道 +- **使用场景**: 离开直播频道时调用 + +#### 5. 发布频道消息 +```dart +Future publishChannelMessage({ + required String channelName, + required String message, + RtmChannelType channelType = RtmChannelType.message, + String? customType, + bool storeInHistory = false, +}) async +``` +- **功能**: 在频道中发布消息 +- **参数**: + - `channelName`: 频道名称 + - `message`: 消息内容(通常是 JSON 字符串) + - `channelType`: 频道类型(默认 message) + - `customType`: 自定义类型(可选) + - `storeInHistory`: 是否存储到历史记录 +- **使用场景**: + - 发送直播间聊天消息 + - 发送礼物消息 + - 发送系统消息(加入/离开房间等) + +#### 6. 登出 +```dart +Future logout() async +``` +- **功能**: 登出 RTM + +#### 7. 刷新 Token +```dart +Future renewToken(String token) async +``` +- **功能**: 刷新 RTM Token(Token 过期时调用) + +### 事件监听 + +#### 消息事件 +```dart +onMessageEvent = (MessageEvent event) { + // 处理频道消息 + final channelName = event.channelName; + final message = event.message; + // 解析消息并处理 +}; +``` + +#### Presence 事件 +```dart +onPresenceEvent = (PresenceEvent event) { + // 处理用户上线/下线事件 +}; +``` + +### 使用示例 + +```dart +// 初始化 RTM +await RTMManager.instance.initialize( + appId: 'your_app_id', + userId: 'user123', +); + +// 订阅频道 +await RTMManager.instance.subscribe('channel_123'); + +// 发布消息 +await RTMManager.instance.publishChannelMessage( + channelName: 'channel_123', + message: json.encode({ + 'type': 'chat', + 'content': 'Hello', + 'userId': 'user123', + }), +); + +// 监听消息事件 +RTMManager.instance.onMessageEvent = (event) { + final message = json.decode(event.message); + print('收到消息: ${message['content']}'); +}; + +// 取消订阅 +await RTMManager.instance.unsubscribe('channel_123'); +``` + +### 注意事项 + +1. **初始化时机**: + - 在应用启动时初始化(`main_page.dart` 的 `initRTM()`) + - 需要用户ID + +2. **Token 管理**: + - 初始化时会自动获取 Token 并登录 + - Token 过期时需要调用 `renewToken()` 刷新 + +3. **频道订阅**: + - 加入直播频道时需要订阅对应的 RTM 频道 + - 离开时需要取消订阅 + +4. **消息格式**: + - 通常使用 JSON 格式 + - 包含 `type` 字段区分消息类型 + +5. **事件处理**: + - 通过回调函数处理事件 + - 需要在初始化后设置回调 + +6. **与 RTCManager 的配合**: + - RTC 负责音视频传输 + - RTM 负责消息传输 + - 两者配合实现完整的直播功能 + +--- + +## ChatController - 聊天控制器 + +### 文件位置 +`lib/controller/message/chat_controller.dart` + +### 功能概述 +负责管理一对一聊天功能,包括: +- 消息发送和接收 +- 消息列表管理 +- 用户信息管理 +- 在线状态订阅 +- 礼物发送 +- 图片/视频/语音消息处理 + +### 核心属性 + +```dart +// 用户ID +final String userId; + +// 用户信息 +final Rx userInfo = Rx(null); + +// 用户在线状态 +final RxBool isUserOnline = RxBool(false); + +// 消息列表 +final RxList messages = RxList([]); + +// 加载更多的游标 +String? _cursor; + +// 礼物产品列表 +final RxList giftProducts = [].obs; +``` + +### 主要方法 + +#### 1. 获取消息列表 +```dart +Future fetchMessages({bool loadMore = false}) async +``` +- **功能**: 获取聊天消息列表 +- **参数**: `loadMore` - 是否加载更多(分页) +- **流程**: + 1. 调用环信 SDK 获取消息 + 2. 添加到消息列表 + 3. 更新游标用于分页 + +#### 2. 发送文本消息 +```dart +Future sendMessage(String content) async +``` +- **功能**: 发送文本消息 +- **参数**: `content` - 消息内容 +- **流程**: + 1. 创建文本消息 + 2. 发送消息 + 3. 添加到本地消息列表 + 4. 标记为已读 + +#### 3. 发送图片消息 +```dart +Future sendImageMessage(String imagePath) async +``` +- **功能**: 发送图片消息 +- **参数**: `imagePath` - 图片本地路径 +- **流程**: + 1. 上传图片到 OSS + 2. 创建图片消息 + 3. 发送消息 + +#### 4. 发送语音消息 +```dart +Future sendVoiceMessage(String filePath, int seconds) async +``` +- **功能**: 发送语音消息 +- **参数**: + - `filePath`: 语音文件路径 + - `seconds`: 语音时长(秒) +- **流程**: + 1. 上传语音文件到 OSS + 2. 创建语音消息 + 3. 发送消息 + +#### 5. 发送视频消息 +```dart +Future sendVideoMessage(String videoPath) async +``` +- **功能**: 发送视频消息 +- **参数**: `videoPath` - 视频文件路径 +- **流程**: + 1. 生成视频缩略图 + 2. 上传视频和缩略图到 OSS + 3. 创建视频消息 + 4. 发送消息 + +#### 6. 发送礼物 +```dart +Future sendGift({ + required GiftProductModel gift, + required int quantity, +}) async +``` +- **功能**: 发送礼物消息 +- **参数**: + - `gift`: 礼物产品模型 + - `quantity`: 礼物数量 +- **流程**: + 1. 调用消费接口 + 2. 检查玫瑰余额 + 3. 创建自定义消息(礼物消息) + 4. 发送消息 + +#### 7. 发送通话消息 +```dart +Future sendCallMessage({ + required String callType, + required String callStatus, + int? callDuration, + String? channelId, + int? uid, +}) async +``` +- **功能**: 发送通话消息(自定义消息) +- **参数**: + - `callType`: 通话类型(voice/video) + - `callStatus`: 通话状态(waitCalling/calling/rejected等) + - `callDuration`: 通话时长(秒) + - `channelId`: RTC 频道ID + - `uid`: RTC 用户ID + +#### 8. 标记消息已读 +```dart +Future markAllMessagesAsRead() async +``` +- **功能**: 将所有消息标记为已读 + +#### 9. 订阅用户在线状态 +```dart +Future subscribeUserPresence() async +``` +- **功能**: 订阅对方用户的在线状态 +- **回调**: 状态变化时会更新 `isUserOnline` + +#### 10. 加载礼物产品列表 +```dart +Future loadGiftProducts() async +``` +- **功能**: 加载可用的礼物产品列表 + +### 使用示例 + +```dart +// 创建 ChatController(在 ChatPage 中) +final controller = Get.put( + ChatController( + userId: targetUserId, + userData: userData, + ), + tag: 'chat_$targetUserId', +); + +// 发送文本消息 +await controller.sendMessage('Hello'); + +// 发送图片 +await controller.sendImageMessage('/path/to/image.jpg'); + +// 发送语音 +await controller.sendVoiceMessage('/path/to/voice.m4a', 10); + +// 发送礼物 +await controller.sendGift( + gift: giftProduct, + quantity: 1, +); + +// 监听消息列表 +Obx(() => ListView.builder( + itemCount: controller.messages.length, + itemBuilder: (context, index) { + final message = controller.messages[index]; + return MessageItem(message: message); + }, +)); + +// 监听在线状态 +Obx(() => Text( + controller.isUserOnline.value ? '在线' : '离线', +)); +``` + +### 注意事项 + +1. **生命周期管理**: + - 在 `onInit()` 中注册到 IMManager + - 在 `onClose()` 中注销 + - 使用 tag 区分不同用户的 Controller + +2. **消息接收**: + - 消息通过 IMManager 自动分发到对应的 ChatController + - 需要先注册到 IMManager + +3. **用户信息**: + - 优先使用环信用户信息 + - 如果没有,使用外部传入的用户数据 + - 会同步到 ConversationController 缓存 + +4. **在线状态**: + - 使用 ChatPresenceManager 订阅 + - 状态变化会实时更新 + +5. **错误处理**: + - 发送失败会显示错误提示 + - 玫瑰不足会显示充值弹框 + - 敏感词会显示错误提示 + +6. **消息去重**: + - 环信 SDK 会自动处理消息去重 + - 本地消息列表使用 RxList 管理 + +7. **文件上传**: + - 图片/视频/语音需要先上传到 OSS + - 上传成功后再发送消息 + +--- + +## 组件间关系 + +### 依赖关系图 + +``` +IMManager (核心) + ├── ChatController (一对一聊天) + │ └── 使用 IMManager 发送/接收消息 + │ + ├── CallController (通话) + │ └── 使用 IMManager 发送通话消息 + │ +RTCManager (音视频) + ├── RoomController (直播) + │ └── 使用 RTCManager 进行音视频传输 + │ + └── CallController (通话) + └── 使用 RTCManager 进行音视频传输 + +RTMManager (消息) + └── RoomController (直播) + └── 使用 RTMManager 发送直播间消息 +``` + +### 交互流程 + +#### 直播流程 +1. **创建直播**: + - `RoomController.createRtcChannel()` + - → `RTCManager.joinChannel()` + - → `RTMManager.subscribe()` + - → 跳转到直播页面 + +2. **发送消息**: + - `RoomController.sendChatMessage()` + - → `RTMManager.publishChannelMessage()` + - → 其他用户通过 RTM 事件接收 + +3. **发送礼物**: + - `RoomController.sendGift()` + - → 调用消费接口 + - → `RTMManager.publishChannelMessage()` + - → SVGA 动画播放 + +#### 聊天流程 +1. **发送消息**: + - `ChatController.sendMessage()` + - → `IMManager.sendMessage()` + - → 环信 SDK 发送 + - → 对方通过 IMManager 接收 + - → 分发到对应的 ChatController + +2. **接收消息**: + - 环信 SDK 接收 + - → `IMManager.onMessagesReceived` + - → 查找对应的 ChatController + - → 添加到消息列表 + +#### 通话流程 +1. **发起通话**: + - `CallController.initiateCall()` + - → 创建 RTC 频道 + - → `RTCManager.joinChannel()` + - → `ChatController.sendCallMessage()` + - → `IMManager` 发送通话消息 + +2. **接听通话**: + - `IMManager` 接收通话消息 + - → 显示邀请弹框 + - → `CallController.acceptCall()` + - → `RTCManager.joinChannel()` + - → 开始通话 + +---