@tencentcloud/sdk-mcp 1.3.4 → 1.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/package.json +1 -1
  2. package/resource/doc/chatuikit/android/features/theme.md +363 -0
  3. package/resource/doc/chatuikit/android/workflow.md +0 -0
  4. package/resource/doc/chatuikit/{android/client_api_android.md → faq/android_sdk/client-api.md} +0 -1
  5. package/resource/doc/chatuikit/faq/{native_sdk/faq.md → common/product.md} +8 -0
  6. package/resource/doc/chatuikit/faq/flutter_sdk/faq.md +54 -0
  7. package/resource/doc/chatuikit/faq/web_sdk/faq.md +1 -1
  8. package/resource/doc/chatuikit/flutter/features/theme.md +379 -0
  9. package/resource/doc/chatuikit/flutter/workflow.md +816 -0
  10. package/resource/doc/chatuikit/iOS/features/theme.md +416 -0
  11. package/resource/doc/chatuikit/iOS/workflow.md +0 -0
  12. package/resource/doc/chatuikit/react/components/chat-setting.md +124 -0
  13. package/resource/doc/chatuikit/react/components/contact-list.md +1331 -0
  14. package/resource/doc/chatuikit/react/components/search.md +885 -0
  15. package/resource/doc/chatuikit/vue/components/chat-setting.md +88 -0
  16. package/resource/doc/chatuikit/vue/components/contact-list.md +679 -0
  17. package/resource/doc/chatuikit/vue/components/search.md +1384 -0
  18. package/resource/doc/livekit/live/android/workflow.md +137 -4
  19. package/resource/doc/livekit/live/flutter/live-audience-list.md +337 -0
  20. package/resource/doc/livekit/live/flutter/live-audio-effect.md +739 -0
  21. package/resource/doc/livekit/live/flutter/live-barrage.md +578 -0
  22. package/resource/doc/livekit/live/flutter/live-base-beauty.md +484 -0
  23. package/resource/doc/livekit/live/flutter/live-co-guest-interaction.md +606 -0
  24. package/resource/doc/livekit/live/flutter/live-gift.md +812 -0
  25. package/resource/doc/livekit/live/flutter/live-host-interaction.md +1113 -0
  26. package/resource/doc/livekit/live/flutter/live-integration.md +1029 -0
  27. package/resource/doc/livekit/live/flutter/live-live-list.md +861 -0
  28. package/resource/doc/livekit/live/ios/live-audience-list.md +335 -0
  29. package/resource/doc/livekit/live/ios/live-audio-effect.md +373 -0
  30. package/resource/doc/livekit/live/ios/live-barrage.md +529 -0
  31. package/resource/doc/livekit/live/ios/live-base-beauty.md +237 -0
  32. package/resource/doc/livekit/live/ios/live-co-guest-interaction.md +483 -0
  33. package/resource/doc/livekit/live/ios/live-gift.md +785 -0
  34. package/resource/doc/livekit/live/ios/live-host-interaction.md +743 -0
  35. package/resource/doc/livekit/live/ios/live-integration.md +822 -0
  36. package/resource/doc/livekit/live/ios/live-live-list.md +535 -0
  37. package/resource/doc/livekit/live/ios/workflow.md +352 -0
  38. package/resource/doc/rtcengine/faq/web/web.md +2 -2
  39. package/resource/doc/rtcengine/web/how_to_integrated_web_sdk.md +2 -2
  40. package/resource/doc/rtcengine/web/plugin/20-advanced-customized-capture-rendering.md +84 -0
  41. package/resource/doc/rtcengine/web/plugin/21-advanced-auto-play-policy.md +86 -0
  42. package/resource/doc/rtcengine/web/plugin/22-advanced-audio-mixer.md +220 -0
  43. package/resource/doc/rtcengine/web/plugin/23-advanced-support-detection.md +217 -0
  44. package/resource/doc/rtcengine/web/plugin/24-advanced-network-quality.md +137 -0
  45. package/resource/doc/rtcengine/web/plugin/25-advanced-device-change.md +97 -0
  46. package/resource/doc/rtcengine/web/plugin/26-advanced-publish-cdn-stream.md +453 -0
  47. package/resource/doc/rtcengine/web/plugin/27-advanced-small-stream.md +180 -0
  48. package/resource/doc/rtcengine/web/plugin/28-advanced-beauty.md +349 -0
  49. package/resource/doc/rtcengine/web/plugin/29-advanced-water-mark.md +149 -0
  50. package/resource/doc/rtcengine/web/plugin/30-advanced-cross-room-link.md +96 -0
  51. package/resource/doc/rtcengine/web/plugin/31-advanced-plugins-overview.md +405 -0
  52. package/resource/doc/rtcengine/web/plugin/34-advanced-proxy.md +244 -0
  53. package/resource/doc/rtcengine/web/plugin/35-advanced-ai-denoiser.md +84 -0
  54. package/resource/doc/rtcengine/web/plugin/36-advanced-virtual-background.md +202 -0
  55. package/resource/doc/rtcengine/web/plugin/37-advanced-voice-changer.md +98 -0
  56. package/resource/doc/rtcengine/web/plugin/38-advanced-basic-beauty.md +95 -0
  57. package/resource/doc/rtcengine/web/plugin/39-advanced-video-decoder.md +33 -0
  58. package/resource/doc/rtcengine/web/plugin/40-advanced-video-mixer.md +380 -0
  59. package/resource/doc/rtcengine/web/plugin/41-advanced-small-stream-auto-switcher.md +91 -0
  60. package/resource/doc/rtcengine/web/plugin/42-advanced-realtime-transcriber.md +314 -0
  61. package/resource/doc/rtcengine/web/plugin/43-advanced-face-detection.md +180 -0
  62. package/tools/chat/get-native-chat-feature-detail.js +30 -0
  63. package/tools/chat/get-native-chat-feature-detail.js.map +1 -0
  64. package/tools/chat/get-native-chat-integration.js +30 -12
  65. package/tools/chat/get-native-chat-integration.js.map +1 -1
  66. package/tools/common/get-faq.js +2 -4
  67. package/tools/common/get-faq.js.map +1 -1
  68. package/tools/definitions/get_native_chat_feature_detail_def.js +32 -0
  69. package/tools/definitions/get_native_chat_feature_detail_def.js.map +1 -0
  70. package/tools/definitions/get_native_chat_uikit_integration_def.js +18 -6
  71. package/tools/definitions/get_native_chat_uikit_integration_def.js.map +1 -1
  72. package/tools/definitions/{get_native_live_extra_features_def.js → get_native_live_uikit_extra_features_def.js} +3 -3
  73. package/tools/definitions/get_native_live_uikit_extra_features_def.js.map +1 -0
  74. package/tools/definitions/{get_native_live_interaction_def.js → get_native_live_uikit_interaction_def.js} +3 -3
  75. package/tools/definitions/get_native_live_uikit_interaction_def.js.map +1 -0
  76. package/tools/definitions/get_web_chat_uikit_component_detail_def.js +46 -7
  77. package/tools/definitions/get_web_chat_uikit_component_detail_def.js.map +1 -1
  78. package/tools/index.js +6 -4
  79. package/tools/index.js.map +1 -1
  80. package/tools/live/{get_native_live_extra_features.js → get_native_live_uikit_extra_features.js} +4 -4
  81. package/tools/live/get_native_live_uikit_extra_features.js.map +1 -0
  82. package/tools/live/{get_native_live_interaction.js → get_native_live_uikit_interaction.js} +4 -4
  83. package/tools/live/get_native_live_uikit_interaction.js.map +1 -0
  84. package/tools/rtcengine/get-trtc-web-sdk-faq.js +1 -1
  85. package/tools/rtcengine/get-trtc-web-sdk-plugin.js +45 -0
  86. package/tools/rtcengine/get-trtc-web-sdk-plugin.js.map +1 -0
  87. package/utils/handle-component-name.js +0 -16
  88. package/utils/handle-component-name.js.map +1 -1
  89. package/utils/report-cls-client.js +1 -1
  90. package/utils/report-es-client.js +1 -1
  91. package/resource/doc/chatuikit/android/integrate_tuichat_only_android.md +0 -382
  92. package/resource/doc/chatuikit/android/ui_api_android.md +0 -418
  93. package/resource/doc/chatuikit/iOS/integrate_tuichat_only_iOS.md +0 -993
  94. package/resource/doc/chatuikit/iOS/ui_api_iOS.md +0 -526
  95. package/tools/definitions/get_native_live_extra_features_def.js.map +0 -1
  96. package/tools/definitions/get_native_live_interaction_def.js.map +0 -1
  97. package/tools/live/get_native_live_extra_features.js.map +0 -1
  98. package/tools/live/get_native_live_interaction.js.map +0 -1
  99. /package/resource/doc/chatuikit/android/{integrate_tuikit_android.md → integration.md} +0 -0
  100. /package/resource/doc/chatuikit/{flutter/client_api_Flutter.md → faq/flutter_sdk/client-api.md} +0 -0
  101. /package/resource/doc/chatuikit/{iOS/client_api_iOS.md → faq/ios_sdk/client-api.md} +0 -0
  102. /package/resource/doc/chatuikit/flutter/{integrate_tuikit_Flutter.md → integration.md} +0 -0
  103. /package/resource/doc/chatuikit/iOS/{integrate_tuikit_iOS.md → integration.md} +0 -0
  104. /package/resource/doc/chatuikit/react/components/{chatheader.md → chat-header.md} +0 -0
  105. /package/resource/doc/chatuikit/vue/components/{chatheader.md → chat-header.md} +0 -0
@@ -51,7 +51,7 @@
51
51
 
52
52
  **功能依赖逻辑(重要)**:
53
53
  1. **基础先行**:必须先使用本工具(`get_native_live_uikit_integration`)完成基础直播(开播/观看/列表)。
54
- 2. **互动叠加**:如果用户需求包含“连麦”、“PK”、“观众列表”,必须**在基础功能完成后**,再调用互动工具(`get_native_live_interaction`)。
54
+ 2. **互动叠加**:如果用户需求包含"连麦"、"PK"、"观众列表",必须**在基础功能完成后**,再调用互动工具(`get_native_live_uikit_interaction`)。
55
55
  3. **空项目处理**:若用户在空项目中直接请求互动功能,Agent **必须先实现基础功能**,再添加互动能力。
56
56
 
57
57
  ---
@@ -90,7 +90,7 @@
90
90
  * **必须查阅 API 文档**:涉及数据模型字段(如 `LiveInfo`),必须查看文档确认字段名(例如确认是 `liveOwner.userName` 而不是 `name`)。
91
91
 
92
92
  ### 2. 🧩 Store 与 Listener 管理约束(生命周期安全)
93
- **核心原因**:SDK 的 `Store.create(liveId)` 通常返回单例或复用实例。使用匿名内部类会导致监听器实例重复注册或被覆盖,引发“主播端不显示”或“仅首次生效”的 Bug。
93
+ **核心原因**:SDK 的 `Store.create(liveId)` 通常返回单例或复用实例。使用匿名内部类会导致监听器实例重复注册或被覆盖,引发"主播端不显示"或"仅首次生效"的 Bug。
94
94
 
95
95
  * **唯一实例原则**:所有 Listener(如 `GiftListener`, `CoGuestListener`, `BarrageListener`)**必须声明为 Activity/Fragment 的成员变量**。
96
96
  * **严禁匿名内部类**:禁止直接在 `addXXXListener(object : ...)` 中写匿名对象。
@@ -139,10 +139,105 @@
139
139
 
140
140
  #### C. 弹幕、礼物与布局 (Barrage, Gift & UI)
141
141
  * **层级要求**:弹幕列表和全屏礼物动画必须使用 `FrameLayout` 或 `RelativeLayout` 覆盖在视频层**之上**。
142
- * **禁止分割**:严禁将屏幕分割为“上视频、下弹幕”,必须是叠加模式。
142
+ * **禁止分割**:严禁将屏幕分割为"上视频、下弹幕",必须是叠加模式。
143
143
  * **键盘适配**:必须在 Manifest 中设置 `android:windowSoftInputMode="adjustNothing"` 或 `adjustPan`,**防止键盘弹起时视频画面变形或上移**。
144
+
145
+ ##### 弹幕输入框 (Barrage Input)
146
+ * **位置**:固定在屏幕底部左侧,与功能按钮(礼物、连麦等)同行。
147
+ * **样式**:半透明圆角背景 + 占位文字「说点什么...」。
148
+ * **键盘适配**:
149
+ * 键盘弹起时,输入框**保持原位置不变**,禁止随键盘上移。
150
+ * 视频画面 `LiveCoreView` 布局固定为 `match_parent`,禁止变形或上移。
151
+ * **必须**在 Manifest 中设置 `android:windowSoftInputMode="adjustNothing"`。
152
+
153
+ ##### 弹幕显示流 (Barrage Display Flow)
154
+ ```
155
+ 发送弹幕:
156
+ 用户输入 → 点击发送/回车 → BarrageStore.sendTextMessage(text) → 本地立即插入弹幕列表
157
+
158
+ 接收弹幕:
159
+ 订阅 BarrageStore.barrageState.barrageList → 收到新消息 → 插入弹幕列表 → 滚动到底部
160
+ ```
161
+ * **数据源**:订阅 `BarrageStore.create(liveId).barrageState.barrageList`。
162
+ * **本地回显**:发送成功后**立即**在本地弹幕列表插入,无需等待服务器回调。
163
+ * **滚动行为**:新消息到达时自动滚动到底部(`recyclerView.scrollToPosition(adapter.itemCount - 1)`)。
164
+ * **消息格式**:`[昵称]: [消息内容]`,昵称使用主题色,内容使用白色。
165
+
144
166
  * **礼物弹幕 (Gift Barrage)**:**如果用户需要集成礼物弹幕**,`onReceiveGift` 事件触发时,**主播端和观众端**都必须在弹幕列表(Message List)中插入礼物消息。严禁仅在观众端显示礼物文本。
145
- * **全屏礼物 (Full-screen Gift)**:**如果用户需要集成全屏礼物**,收到礼物回调后,**主播端和观众端**都必须在视频顶层播放全屏动画。严禁只在观众端播放动画,主播也必须能看到观众送出的礼物特效。
167
+
168
+ ##### 全屏礼物动画 (Full-screen Gift Animation)
169
+ **⚠️ 必须实现**:礼物功能集成时,全屏礼物动画是**强制要求**,不可省略。
170
+
171
+ * **层级**:全屏礼物动画视图必须覆盖在 `LiveCoreView` **之上**,使用独立的 `FrameLayout` 容器。
172
+ * **布局**:约束为 `match_parent`,覆盖整个屏幕。
173
+ * **双端同步**:收到 `GiftStore.onReceiveGift` 回调后,**主播端和观众端**都必须播放全屏动画。严禁只在观众端播放。
174
+
175
+ ### 🎨 默认 UI/UX 设计与交互规范 (仅在用户未指定时生效)
176
+
177
+ **⚠️ 注意:以下规范仅在用户未提供具体 UI 设计图或需求时作为默认标准执行。**
178
+
179
+ ### 1. 全局视觉风格 (Global Aesthetics)
180
+ * **沉浸式暗黑**:直播页背景必须为 `Color.BLACK`,视频层 (`LiveCoreView`) 必须**全屏铺满** (`match_parent`) 且位于最底层。
181
+ * **安全区域**:所有悬浮 UI 必须考虑状态栏和导航栏,严禁被刘海屏或底部导航条遮挡。
182
+ * **文字可读性**:视频之上的白色文字(如弹幕、ID)必须添加**黑色阴影** (`setShadowLayer`)。
183
+ * **错误提示**:统一使用 **Toast**,禁止使用模态 AlertDialog 打断用户。
184
+
185
+ ### 2. 通用组件规范 (Component Standards)
186
+ * **顶部胶囊 (Glass Capsule)**:
187
+ * **样式**:**半透明黑色背景** + **全圆角** (`cornerRadius = height / 2`)。
188
+ * **应用**:仅用于顶部左侧展示"主播头像+ID+热度"。
189
+ * **通用按钮 (Flat Buttons)**:
190
+ * **样式**:**"文字 + 圆角矩形背景"**。视觉风格扁平简约,背景色为半透明黑或主题色。
191
+ * **关闭按钮**:特例,使用圆形半透明背景图标。
192
+ * **弹出面板 (Floating Panels)**:
193
+ * **样式**:仅顶部大圆角 (`topLeftRadius, topRightRadius`)。
194
+ * **禁忌**:底部禁止出现非透明的实色背景块,必须保持悬浮感。
195
+
196
+ ### 3. 直播间布局蓝图 (Live Room Layout)
197
+ **⚠️ 动态布局原则:仅渲染用户实际集成的功能按钮。若用户未请求某功能(如PK/美颜),严禁添加对应的空按钮**
198
+
199
+ #### A. 顶部栏 (Top Bar)
200
+ * **左侧 [房间信息]**:使用 **半透明胶囊** 包裹 [主播头像 | 主播昵称]。
201
+ * **右侧 [控制区]**:横向排列 [在线观众人数] + [关闭图标(X)]。
202
+
203
+ #### B. 底部栏 (Bottom Bar) - 根据状态动态切换
204
+ * **预览模式 (Preview)**:
205
+ * 内容**向右靠拢**:[美颜] [音效] [开始直播(主按钮)]。
206
+ * **直播模式 (Anchor Live)**:
207
+ * **左侧**:[弹幕列表(背景透明)] + [聊天输入框]。
208
+ * **右侧**:功能阵列 [美颜] [音效] [连线] [PK]。
209
+ * **观众模式 (Audience Live)**:
210
+ * **左侧**:[弹幕列表] + [聊天输入框]。
211
+ * **右侧**:[礼物] [申请连麦]。
212
+
213
+ ### 4. 首页布局与交互 (Home Interaction)
214
+
215
+ #### A. 首页参考布局
216
+ ```
217
+ ┌─────────────────────────────┐
218
+ │ AtomicXCore 直播 │
219
+ │ │
220
+ │ 直播间 ID │
221
+ │ ┌─────────────────────────┐│
222
+ │ │ live_000001 ││ ← 输入框 (带左侧 Padding, 半透明背景)
223
+ │ └─────────────────────────┘│
224
+ │ │
225
+ │ 主播开播 │
226
+ │ (点击即以 anchor001 登录) │
227
+ │ │
228
+ │ 观众观看 │
229
+ │ (点击即以 user001 登录) │
230
+ │ │
231
+ │ [ 📋 直播列表 ] │
232
+ └─────────────────────────────┘
233
+ ```
234
+
235
+ #### B. 隐式登录流程
236
+ **首页不需要单独的登录按钮**,登录在点击功能按钮时自动完成:
237
+ * 点击「主播开播」→ 使用 `anchor001` 登录 → 跳转主播页。
238
+ * 点击「观众观看」→ 使用 `user001` 登录 → 跳转观众页。
239
+ * 点击「直播列表」→ 使用 `user001` 登录 → 跳转列表页。
240
+
146
241
  ---
147
242
 
148
243
  ## 🎯 功能实现细节
@@ -162,6 +257,44 @@
162
257
  * **数据**:订阅 `liveState.liveList`。
163
258
  * **跳转**:点击列表项跳转观众页,传递 `liveID`。
164
259
 
260
+ ### 4. 连麦与连线交互规范 (`co_guest` & `co_host`)
261
+
262
+ #### A. 观众连麦(主播被动接收)
263
+ * **主播端 UI**:❌ **严禁**在底部工具栏或任何位置显示「连麦申请」列表按钮。
264
+ * **交互逻辑**:当收到观众连麦申请回调时,直接在屏幕中心弹出对话框(`AlertDialog`):
265
+ * **标题**:连麦申请
266
+ * **内容**:收到观众 [昵称] 的连麦申请,是否接受?
267
+ * **操作**:[拒绝] [接受]
268
+
269
+ #### B. 主播连线面板(点击底部【连线】按钮弹出)
270
+ * **展现形式**:使用底部浮层面板(`BottomSheetDialog` 或自定义 `View` 动画升起),禁止使用 `AlertDialog`。
271
+ * **UI 布局(严格对照图示)**:
272
+ ```
273
+ ┌─────────────────────────────────────┐
274
+ │ │
275
+ │ 发起连线 [🚪 结束连线] │ ← 红色文字
276
+ │ │
277
+ │ 连线中 (2 人) │
278
+ │ ┌─────────────────────────────────┐│
279
+ │ │ [👤] 李子明 [💎20] PK中... ││ ← 已连线用户
280
+ │ │ [👤] 菲林娜 [💎32] PK中... ││
281
+ │ └─────────────────────────────────┘│
282
+ ├─────────────────────────────────────┤
283
+ │ 其他连线用户 │
284
+ │ ┌─────────────────────────────────┐│
285
+ │ │ [👤] 李子明 [💎20] [取消邀请] ││ ← 灰黑背景按钮
286
+ │ │ [👤] 菲林娜 [💎32] [邀请连线] ││ ← 蓝色背景按钮
287
+ │ │ [👤] 铁柱 [💗99] [邀请连线] ││
288
+ │ └─────────────────────────────────┘│
289
+ └─────────────────────────────────────┘
290
+ ```
291
+
292
+ #### C. PK 按钮交互约束
293
+ * **前置检查**:点击底部【PK】按钮时,必须检查当前连线状态(`CoHostStore.connectedUsers.isEmpty()`)。
294
+ * **状态处理**:
295
+ * **未连线**:❌ 禁止跳转,使用 Toast 提示:`"请先发起连线"`。
296
+ * **已连线**:✅ 弹出 PK 邀请面板。
297
+
165
298
  ---
166
299
 
167
300
  ## 📋 Agent 最终检查清单
@@ -0,0 +1,337 @@
1
+ `LiveAudienceStore` 是 `AtomicXCore` 中专门负责管理直播间观众信息的模块。通过 `LiveAudienceStore`,您可以为您的直播应用构建一套完整的观众列表及管理系统。
2
+
3
+ ![](https://write-document-release-1258344699.cos.ap-guangzhou.tencentcos.cn/100032457995/b6e6ff5cdca611f0be395254005ef0f7.png)
4
+
5
+
6
+ ## 核心功能
7
+ - **实时观众列表**:获取并展示当前在直播间内的所有观众信息。
8
+
9
+ - **观众人数统计**:实时获取当前直播间的准确观众总数。
10
+
11
+ - **观众动态监听**:通过事件订阅,实时感知观众的加入和离开。
12
+
13
+ - **管理员权限**:主播可以将普通观众设为管理员,或撤销其管理员身份。
14
+
15
+ - **房间管理**:主播或管理员可以将任意普通观众请出(踢出)直播间。
16
+
17
+
18
+ ## 核心概念
19
+
20
+ 下表介绍了 `LiveAudienceStore` 的核心概念:
21
+ <table>
22
+ <tr>
23
+ <td rowspan="1" colSpan="1" >**核心概念**</td>
24
+
25
+ <td rowspan="1" colSpan="1" >**类型**</td>
26
+
27
+ <td rowspan="1" colSpan="1" >**核心职责与描述**</td>
28
+ </tr>
29
+
30
+ <tr>
31
+ <td rowspan="1" colSpan="1" >[LiveUserInfo](https://tencent-rtc.github.io/TUIKit_Flutter/api_live_live_audience_store/LiveUserInfo-class.html)</td>
32
+
33
+ <td rowspan="1" colSpan="1" >`class`</td>
34
+
35
+ <td rowspan="1" colSpan="1" >代表一个观众(用户)的基础信息模型。它包含了用户的唯一标识 (`userID`)、昵称 (`userName`) 和头像地址 (`avatarURL`)。</td>
36
+ </tr>
37
+
38
+ <tr>
39
+ <td rowspan="1" colSpan="1" >[LiveAudienceState](https://tencent-rtc.github.io/TUIKit_Flutter/api_live_live_audience_store/LiveAudienceState-class.html)</td>
40
+
41
+ <td rowspan="1" colSpan="1" >`class`</td>
42
+
43
+ <td rowspan="1" colSpan="1" >代表观众模块的当前状态。其核心属性 `audienceList` 是一个 `ValueListenable<List<LiveUserInfo>>`,存储了观众列表的快照;`audienceCount` 则代表当前观众总数。</td>
44
+ </tr>
45
+
46
+ <tr>
47
+ <td rowspan="1" colSpan="1" >[LiveAudienceListener](https://tencent-rtc.github.io/TUIKit_Flutter/api_live_live_audience_store/LiveAudienceListener-class.html)</td>
48
+
49
+ <td rowspan="1" colSpan="1" >`class`</td>
50
+
51
+ <td rowspan="1" colSpan="1" >代表观众动态的实时事件监听器。包含 `onAudienceJoined`(观众加入)和 `onAudienceLeft`(观众离开)两个回调,用于实现对观众列表的增量更新。</td>
52
+ </tr>
53
+
54
+ <tr>
55
+ <td rowspan="1" colSpan="1" >[LiveAudienceStore](https://tencent-rtc.github.io/TUIKit_Flutter/api_live_live_audience_store/LiveAudienceStore-class.html)</td>
56
+
57
+ <td rowspan="1" colSpan="1" >`class`</td>
58
+
59
+ <td rowspan="1" colSpan="1" >这是与观众列表功能交互的核心管理类。通过它,您可以获取观众列表快照、执行管理操作,并通过 `addLiveAudienceListener` 来接收实时动态。</td>
60
+ </tr>
61
+ </table>
62
+
63
+
64
+ ## 实现步骤
65
+
66
+ ### 步骤1:组件集成
67
+
68
+ 请参考 [开始直播](https://write.woa.com/document/191126413785100288) 集成 **AtomicXCore**,完成接入。
69
+
70
+ ### 步骤2:初始化并获取观众列表
71
+
72
+ 获取一个与当前直播间 liveId 绑定的 `LiveAudienceStore` 实例,并主动拉取一次当前的观众列表,用于首次展示。
73
+
74
+ 在退出直播间时可通过调用 `AudienceManager` 的 `dispose` 方法回收资源。
75
+ ``` java
76
+ import 'package:atomic_x_core/atomicxcore.dart';
77
+
78
+ class AudienceManager {
79
+ final String liveId;
80
+ late final LiveAudienceStore audienceStore;
81
+ late LiveAudienceListener _audienceListener;
82
+ late final VoidCallback _audienceListChangedListener = _onAudienceListChanged;
83
+ late final VoidCallback _audienceCountChangedListener = _onAudienceCountChanged;
84
+
85
+ // 对外暴露【全量】观众列表
86
+ List<LiveUserInfo> audienceList = [];
87
+ // 对外暴露观众总数
88
+ int audienceCount = 0;
89
+
90
+ // 状态变更回调
91
+ Function()? onStateChanged;
92
+
93
+ AudienceManager({required this.liveId}) {
94
+ // 1. 通过 liveId 获取 LiveAudienceStore 的实例
95
+ audienceStore = LiveAudienceStore.create(liveId);
96
+
97
+ // 2. 订阅状态和事件
98
+ _subscribeToAudienceState();
99
+ _subscribeToAudienceEvents();
100
+
101
+ // 3. 主动拉取首屏数据
102
+ fetchInitialAudienceList();
103
+ }
104
+
105
+ /// 主动获取一次观众列表快照
106
+ Future<void> fetchInitialAudienceList() async {
107
+ final result = await audienceStore.fetchAudienceList();
108
+ if (result.isSuccess) {
109
+ print("首次拉取观众列表成功");
110
+ // 成功后,数据会通过下面的 state 订阅通道自动更新
111
+ } else {
112
+ print("首次拉取观众列表失败: ${result.errorMessage}");
113
+ }
114
+ }
115
+
116
+ void dispose() {
117
+ audienceStore.liveAudienceState.audienceList.removeListener(_audienceListChangedListener);
118
+ audienceStore.liveAudienceState.audienceCount.removeListener(_audienceCountChangedListener);
119
+ audienceStore.removeLiveAudienceListener(_audienceListener);
120
+ }
121
+ }
122
+ ```
123
+
124
+ 观众列表等 `state` 订阅将在下一步骤详细讲解。
125
+
126
+ ### 步骤3:监听观众列表状态与实时动态
127
+
128
+ 订阅 `audienceStore` 的 `liveAudienceState` 和 `LiveAudienceListener`,以接收全量列表快照和实时的观众进出事件,从而驱动 UI 更新。
129
+ ``` java
130
+ extension AudienceManagerSubscription on AudienceManager {
131
+ /// 订阅 state,用于获取观众总数和列表快照
132
+ void _subscribeToAudienceState() {
133
+ // 监听观众列表变化
134
+ audienceStore.liveAudienceState.audienceList.addListener(_audienceListChangedListener);
135
+ // 监听观众人数变化
136
+ audienceStore.liveAudienceState.audienceCount.addListener(_audienceCountChangedListener);
137
+ }
138
+
139
+ void _onAudienceListChanged() {
140
+ // audienceList 是一个全量快照
141
+ audienceList = audienceStore.liveAudienceState.audienceList.value;
142
+ onStateChanged?.call();
143
+ }
144
+
145
+ void _onAudienceCountChanged() {
146
+ // audienceCount 是实时总数
147
+ audienceCount = audienceStore.liveAudienceState.audienceCount.value;
148
+ onStateChanged?.call();
149
+ }
150
+
151
+ /// 订阅 event,用于处理观众的实时进出
152
+ void _subscribeToAudienceEvents() {
153
+ _audienceListener = LiveAudienceListener(
154
+ onAudienceJoined: (audience) {
155
+ print("观众 ${audience.userName} 加入了直播间");
156
+ // 增量更新:在当前列表末尾添加新观众
157
+ if (!audienceList.any((a) => a.userID == audience.userID)) {
158
+ audienceList.add(audience);
159
+ onStateChanged?.call();
160
+ }
161
+ },
162
+ onAudienceLeft: (audience) {
163
+ print("观众 ${audience.userName} 离开了直播间");
164
+ // 增量更新:从当前列表中移除离开的观众
165
+ audienceList.removeWhere((a) => a.userID == audience.userID);
166
+ onStateChanged?.call();
167
+ },
168
+ );
169
+ audienceStore.addLiveAudienceListener(_audienceListener);
170
+ }
171
+ }
172
+ ```
173
+
174
+ ### 步骤4:管理观众(踢人与设置管理员)
175
+
176
+ 作为主播或管理员,对直播间内的观众进行管理操作。
177
+
178
+ #### 4.1 将观众踢出直播间
179
+
180
+ 调用 `kickUserOutOfRoom` 接口可以将指定用户请出直播间。
181
+ ``` java
182
+ extension AudienceManagerActions on AudienceManager {
183
+ Future<void> kick(String userId) async {
184
+ final result = await audienceStore.kickUserOutOfRoom(userId);
185
+ if (result.isSuccess) {
186
+ print("成功将用户 $userId 踢出房间");
187
+ // 踢出成功后,您会收到 onAudienceLeft 事件
188
+ } else {
189
+ print("踢出用户 $userId 失败: ${result.errorMessage}");
190
+ }
191
+ }
192
+ }
193
+ ```
194
+
195
+ #### 4.2 设置/撤销管理员
196
+
197
+ 通过 `setAdministrator` 和 `revokeAdministrator` 接口可以管理用户的管理员身份。
198
+ ``` java
199
+ extension AudienceManagerAdmin on AudienceManager {
200
+ /// 将用户设为管理员
201
+ Future<void> promoteToAdmin(String userId) async {
202
+ final result = await audienceStore.setAdministrator(userId);
203
+ if (result.isSuccess) {
204
+ print("成功将用户 $userId 设为管理员");
205
+ }
206
+ }
207
+
208
+ /// 撤销用户的管理员身份
209
+ Future<void> revokeAdmin(String userId) async {
210
+ final result = await audienceStore.revokeAdministrator(userId);
211
+ if (result.isSuccess) {
212
+ print("成功撤销用户 $userId 的管理员身份");
213
+ }
214
+ }
215
+ }
216
+ ```
217
+
218
+ ## 功能进阶
219
+
220
+ ### 在弹幕区展示观众入场欢迎语
221
+
222
+ 当有新观众进入直播间时,弹幕/聊天区域会在本地自动显示一条欢迎消息,例如:"欢迎 [用户昵称] 进入直播间"。
223
+
224
+ #### 实现方式
225
+
226
+ 我们通过订阅 `LiveAudienceStore` 的观众加入事件(`onAudienceJoined`)来获取新观众加入的实时通知。一旦事件触发,我们便提取出新观众的昵称信息,然后立即调用 `BarrageStore` 的本地插入接口 `appendLocalTip`。
227
+
228
+ 在退出直播间时可通过调用 `LiveRoomManager` 的 `dispose` 方法回收资源。
229
+ ``` java
230
+ import 'package:atomic_x_core/atomicxcore.dart';
231
+
232
+ class LiveRoomManager {
233
+ final String liveId;
234
+ late LiveAudienceListener _welcomeListener;
235
+
236
+ LiveRoomManager({required this.liveId}) {
237
+ _setupWelcomeMessageFlow();
238
+ }
239
+
240
+ void _setupWelcomeMessageFlow() {
241
+ // 1. 获取 LiveAudienceStore 的实例
242
+ final audienceStore = LiveAudienceStore.create(liveId);
243
+
244
+ // 2. 获取 BarrageStore 的实例 (得益于内部机制,这会是同一个实例)
245
+ final barrageStore = BarrageStore.create(liveId);
246
+
247
+ // 3. 订阅观众事件
248
+ _welcomeListener = LiveAudienceListener(
249
+ onAudienceJoined: (audience) {
250
+ // 4. 创建一条本地提示消息
251
+ final welcomeTip = Barrage(
252
+ messageType: BarrageType.text,
253
+ textContent: "欢迎 ${audience.userName} 进入直播间!",
254
+ );
255
+
256
+ // 5. 调用 BarrageStore 的接口将其插入弹幕列表
257
+ barrageStore.appendLocalTip(welcomeTip);
258
+ },
259
+ );
260
+ audienceStore.addLiveAudienceListener(_welcomeListener);
261
+ }
262
+
263
+ void dispose() {
264
+ final audienceStore = LiveAudienceStore.create(liveId);
265
+ audienceStore.removeLiveAudienceListener(_welcomeListener);
266
+ }
267
+ }
268
+ ```
269
+
270
+ ## API 文档
271
+
272
+ 关于 [LiveAudienceStore](https://tencent-rtc.github.io/TUIKit_Flutter/api_live_live_audience_store/LiveAudienceStore-class.html) 及其相关类的所有公开接口、属性和方法的详细信息,请参考 [AtomicXCore](https://tencent-rtc.github.io/TUIKit_Flutter/index.html) 框架的官方 API 文档。本文档使用到的相关 Store 如下:
273
+ <table>
274
+ <tr>
275
+ <td rowspan="1" colSpan="1" >**Store/Component**</td>
276
+
277
+ <td rowspan="1" colSpan="1" >**功能描述**</td>
278
+
279
+ <td rowspan="1" colSpan="1" >**API 文档**</td>
280
+ </tr>
281
+
282
+ <tr>
283
+ <td rowspan="1" colSpan="1" >**LiveCoreWidget**</td>
284
+
285
+ <td rowspan="1" colSpan="1" >直播视频流展示与交互的核心视图组件:负责视频流渲染和视图挂件处理,支持主播直播、观众连麦、主播连线等场景。</td>
286
+
287
+ <td rowspan="1" colSpan="1" >[API 文档](https://tencent-rtc.github.io/TUIKit_Flutter/api_view_live_live_core_widget/LiveCoreWidget-class.html)</td>
288
+ </tr>
289
+
290
+ <tr>
291
+ <td rowspan="1" colSpan="1" >**LiveCoreController**</td>
292
+
293
+ <td rowspan="1" colSpan="1" >LiveCoreWidget 的控制器:用于设置直播 ID、控制预览等操作。</td>
294
+
295
+ <td rowspan="1" colSpan="1" >[API 文档](https://tencent-rtc.github.io/TUIKit_Flutter/api_view_live_live_core_widget/LiveCoreController-class.html)</td>
296
+ </tr>
297
+
298
+ <tr>
299
+ <td rowspan="1" colSpan="1" >**LiveAudienceStore**</td>
300
+
301
+ <td rowspan="1" colSpan="1" >观众管理:获取实时观众列表(ID / 名称 / 头像),统计观众数量,监听观众进出事件。</td>
302
+
303
+ <td rowspan="1" colSpan="1" >[API 文档](https://tencent-rtc.github.io/TUIKit_Flutter/api_live_live_audience_store/LiveAudienceStore-class.html)</td>
304
+ </tr>
305
+
306
+ <tr>
307
+ <td rowspan="1" colSpan="1" >**BarrageStore**</td>
308
+
309
+ <td rowspan="1" colSpan="1" >弹幕功能:发送文本 / 自定义弹幕,维护弹幕列表,实时监听弹幕状态。</td>
310
+
311
+ <td rowspan="1" colSpan="1" >[API 文档](https://tencent-rtc.github.io/TUIKit_Flutter/api_barrage_barrage_store/api_barrage_barrage_store-library.html)</td>
312
+ </tr>
313
+ </table>
314
+
315
+
316
+ ## 常见问题
317
+
318
+ ### `LiveAudienceState` 中的在线人数(`audienceCount`)是如何更新的?时机和频率是怎样的?
319
+
320
+ `audienceCount` 的更新并非总是实时的,其机制如下:
321
+ - **主动进出房间**:当用户主动加入或正常退出直播间时,在线人数的变更通知会即时触发。您会很快在 `LiveAudienceState` 中观察到 `audienceCount` 的变化。
322
+
323
+ - **异常掉线**:当用户因网络问题、应用崩溃等原因异常掉线时,系统需要通过心跳机制来判断其真实状态。只有当该用户连续 90 秒没有心跳后,系统才会判定其为离线,并触发人数变更通知。
324
+
325
+ - **更新机制与频率控制:**
326
+
327
+ - 无论是即时触发还是延迟触发,所有的人数变更通知都是以消息的形式在房间内广播的。
328
+
329
+ - 房间内每秒的消息总量有上限,单房间消息频控是**每秒 40 条消息**。
330
+
331
+ - **关键点:**在"弹幕风暴"或礼物刷屏等消息流量极高的场景下,如果房间内的消息速率超过了 40条/秒 的阈值,为了保证核心消息(例如弹幕)的送达,**人数变更的消息可能会被频控策略丢弃**。
332
+
333
+
334
+ **这对开发者意味着什么?**
335
+
336
+
337
+ `audienceCount` 是一个非常接近实时的**高精度估算值**,但在极端高并发场景下,它可能存在短暂的延迟或数据丢失。因此,我们建议您将其用于 **UI 展示**,而不应作为计费、统计等需要绝对精准场景的唯一依据。