关于 stream-flutter
stream-flutter 是面向 Flutter 项目中 Stream Chat、Video 和 Feeds 工作的技能路由器,按用户意图选择新建、集成、文档查询或迁移流程。它还指导聊天 UI 策略、组件定制与设计核验。
主要功能
- 01按意图选择工作流程
- 02识别新建、集成与迁移任务
- 03提供聊天 UI 策略指导
- 04说明组件定制与设计核验
适用场景
- 01为 Flutter 应用接入 Stream Chat
- 02创建 Stream 视频或 Feeds 应用
- 03查询 Stream Flutter 文档与组件
- 04将 Flutter 应用从 Sendbird 迁移
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ getstream/ agent-skills --skill stream-flutter安装后在 Claude Code 中输入/stream-flutter确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
builder.mdcustom-ui.mddesign-matching.mdRULES.mdsdk.mdsendbird-migration.mdreferences/CHAT-ADVANCED-FLUTTER-blueprints.mdCHAT-ADVANCED-FLUTTER.mdCHAT-CORE-blueprints.mdCHAT-CORE.mdCHAT-FLUTTER-blueprints.mdCHAT-FLUTTER.mdFEEDS-FLUTTER-blueprints.mdFEEDS-FLUTTER.mdLIVESTREAM-FLUTTER-blueprints.mdLIVESTREAM-FLUTTER.mdRINGING-FLUTTER-blueprints.mdRINGING-FLUTTER.mdVIDEO-ADVANCED-FLUTTER-blueprints.mdVIDEO-ADVANCED-FLUTTER.mdVIDEO-FLUTTER-blueprints.mdVIDEO-FLUTTER.md详细介绍
Stream Flutter - 技能路由器 + 执行流程
**规则:**每个会话只需阅读一次 RULES.md——所有不可协商的规则都写在其中,不会在其他地方说明。
此文件是 唯一入口:用于在 Flutter 应用中进行 Stream 相关工作的意图分类、本地项目检测和模块指引。
步骤 0:意图分类器(必须首先执行,不得跳过)
在调用任何工具之前,仅根据用户输入确定 轨道——不得先进行探测。
信号 -> 轨道
| 用户输入中的信号 | 路径 |
|---|---|
明确的软件包/组件标识:stream_chat_flutter、StreamChannelListView、StreamMessageListView、StreamChatClient 等。 | C - 参考查询 |
明确的视频标识:stream_video_flutter、StreamCallContainer、StreamVideo、StreamVideoRenderer、goLive、stopLive、livestream 通话类型 | C - 参考查询 |
明确的 Feeds 标识:stream_feed、stream_feed_flutter_core、StreamFeedClient、FlatFeedCore、FlatFeed、FeedBloc、activity feed、feeds flutter | C - 参考查询 |
| Stream Flutter 相关内容中出现“docs”或“documentation” | C - 参考查询 |
| “How do I {X} in Flutter?”、“What does {widget/method} do?” | C - 参考查询 |
| “Build me a new Flutter app”、“create a Flutter chat app” + Stream | A - 新建应用 |
| “Build a Flutter video call app”、“create a livestream app in Flutter” | A - 新建应用(加载 VIDEO-FLUTTER.md + VIDEO-FLUTTER-blueprints.md 或 LIVESTREAM-FLUTTER.md + LIVESTREAM-FLUTTER-blueprints.md) |
| “Build an audio room / Twitter Spaces clone”、“TikTok-style live feed”、“call while livestreaming”、“chat with video calls”、“two calls at once” | A 或 B(在 Video/Livestream 文档组基础上加载 VIDEO-ADVANCED-FLUTTER.md + VIDEO-ADVANCED-FLUTTER-blueprints.md) |
| “Add ringing / incoming calls”、“video call with push notifications”、“CallKit”、“VoIP push”、“FCM ringing”、“missed call notification” | A 或 B(在 Video 文档组基础上加载 RINGING-FLUTTER.md + RINGING-FLUTTER-blueprints.md) |
| “Build a Flutter feeds app”、“create an activity feed app”、“build a social feed in Flutter”、“create a Twitter/Instagram clone” | A - 新建应用(加载 FEEDS-FLUTTER.md + FEEDS-FLUTTER-blueprints.md;除非用户明确指定其他样式,否则使用 Twitter 风格的 UI) |
| “Add/integrate Stream into this app”、“wire Chat into my Flutter project” | B - 现有应用 |
| “Add video calling to my Flutter app”、“integrate Stream Video into my existing app” | B - 现有应用(加载 VIDEO-FLUTTER.md + VIDEO-FLUTTER-blueprints.md) |
| “Add a feed to my Flutter app”、“integrate Stream Feeds into my existing app”、“add activity feed” | B - 现有应用(加载 FEEDS-FLUTTER.md + FEEDS-FLUTTER-blueprints.md;除非用户明确指定其他样式,否则使用 Twitter 风格的 UI) |
| “Install Stream packages”、“set up Stream in Flutter”、“wire auth/token”,且没有更广泛的功能需求 | D - 引导/设置 |
“Migrate my Flutter app from Sendbird”、“replace sendbird_chat_sdk / sendbird_uikit with Stream”、“switch off Sendbird / SendbirdUIKit” | M - 从 Sendbird 迁移(sendbird-migration.md) |
不带参数的 /stream-flutter | 简要列出各路径并等待 |
样式深度标记(与 Track A/B/C/D 正交)
如果请求中包含目标外观——附带的截图、Figma 画板,或“让它看起来像 WhatsApp / iMessage / Telegram / Slack / ”——那么在开始功能开发(Track A 或 B)之前,先运行下面的策略决策(组件还是自定义):
- 组件 → 运行
design-matching.md:完整阅读其中的流程部分——也就是# Reference分隔线之前的所有内容(步骤 1–5;可能需要分两次读取,因此如果流程中途被截断,请继续翻阅)——然后在实现过程中,按区域检索其 Reference 部分。 - 自定义(直播 / 叠加层 / 定制设计)→ 改为运行
custom-ui.md,同样逐区域严谨处理,但采用不同机制。
本节其余内容针对组件情况(最常见的情况)。参考设计是一份区域清单(标题、编辑框按钮、时间戳和已读回执的位置、气泡形状/尾巴、日期分隔线、附件……),其中大多数与 Stream 默认样式的差异在结构上,而不仅仅是颜色。不要只调整壁纸和气泡颜色——这是已知的失败模式。先分解每个区域(记录其尺寸,而不只是颜色),再将每个区域归入以下两个方向之一:
- 主题化——
StreamTheme(MaterialApp.theme.extensions上的ThemeExtension)负责设计基础(间距 / 圆角 / 字体排版 / 颜色)以及所有细粒度/叶子样式,包括整行消息(messageItemTheme气泡/文本/附件/元数据、reactionsTheme、reactionPickerTheme、avatarTheme、textInputTheme、mediaViewerTheme等);StreamChatThemeData(传入StreamChat(themeData:))只负责聊天复合组件的插槽(三种标题、消息列表背景/壁纸、频道列表项、引用消息、线程磁贴、投票主题)。 - 替换组件——组件工厂通过
StreamComponentBuilders(...)中的核心命名插槽填充(约 48 个叶子插槽:messageBubble、messageText、reactions、reactionPicker、mediaViewer、jumpToUnreadButton、textInput、avatar等),以及通过streamChatComponentBuilders(...) → extensions:填充的聊天插槽(约 30 个复合插槽:messageItem、messageComposer+ 子插槽、channelListItem、各类附件构建器等);将它们传入StreamChat(componentBuilders: StreamComponentBuilders(...))(全局)或StreamComponentFactory(builders: …, child: …)(局部作用域);单个实例还可使用各组件自己的构建器(messageBuilder、itemBuilder)。
文档重点防范的常见陷阱:
- (a) 覆盖复合组件(
messageItem构建器、messageComposer构建器、StreamMessageListView上的messageBuilder)会悄然丢弃默认实现渲染的子功能——收到消息时的头像、分组、表情反应、回复、状态或发送/语音/编辑/慢速模式按钮——除非你阅读默认实现的build()并将这些功能复现出来(在自定义messageItem中,可通过StreamMessageLayout.of(context)获取分组状态); - (b) 由模型驱动的标题逻辑必须放在一个供频道列表
itemBuilder和标题栏共同使用的辅助函数中,以避免两个界面逻辑不一致; - (c) 有意选择实现路径——气泡内边距 / 颜色 / 形状由
StreamTheme(StreamTheme.messageItemTheme.bubble)控制。结构性改动(发送按钮位于输入框外、元数据位于气泡内、气泡尾巴、Slack 风格的扁平行)则需要替换组件(使用组件工厂或单组件构建器)。 直到你运行应用、准备能够触发每个区域的数据、沿真实导航路径逐区域与参考进行比较并反复迭代后,匹配工作才算完成(design-matching.md第 5 步);删除任何临时搭建的验证脚手架——UI 必须尽可能贴近参考,而不是大致相似。实现每个区域,包括消息输入框——绝不要交付只完成部分匹配、并把其余部分标为“已知的外观差异”的版本;某个区域仍保留 SDK 默认样式就算不合格,不能只当作附注。还要分批处理:一次性确认固定的 SDK 版本和本地检出版本,一次性阅读所需源码,实现所有区域,然后在热重载时验证一次——不要每做一处小修改就重新构建并截图。
仅针对聊天:先选择 UI 策略(编写任何代码之前)
Stream Chat 提供两个层次,选择哪一层是一个远超样式选择的架构决策——选错无论如何都会浪费一天。因此要审慎决定,并且默认选择预构建组件:
| 策略 | 适用的设计…… | 实现方式 | 操作指南 |
|---|---|---|---|
预构建 UI 组件(stream_chat_flutter)——默认选择 | 即时通信界面:气泡,或频道列表 → 对话,或每条消息都带头像/时间戳/回执/表情反应/附件。社交、市场平台、职场、支持服务、私信。“做成 WhatsApp / iMessage / Telegram / Slack 的样子。” | 通过两个维度进行自定义——主题(基础样式使用 StreamTheme,消息行/叶子组件使用 StreamTheme,聊天复合组件使用 StreamChatThemeData)+ 替换 widget(组件工厂 StreamComponentBuilders / streamChatComponentBuilders / StreamComponentFactory,以及各 widget 的构建器) | design-matching.md |
在 stream_chat_flutter_core 上构建自定义 UI——例外情况 | 非即时通信界面:无气泡、作者信息内联的平铺信息流;视频上的叠层/滚动字幕;高流量、短暂的直播聊天(Twitch / YouTube / Kalshi);直播购物;或匿名/访客只读观众远多于发帖者的场景(→ livestream 频道类型)。每条消息的呈现方式都相同;周边应用界面则完全自定义。 | 基于无头的 stream_chat_flutter_core 控制器(+ 低层客户端)构建自己的 widget;不使用 stream_chat_flutter widget | custom-ui.md |
优先选择组件。 这些组件本来就是为自定义而构建的,判断标准是:如果通过两个维度——主题(StreamTheme + StreamChatThemeData)和少数几个组件构建器插槽——就能实现目标,那就应该使用组件——即便要对即时通信界面进行大幅改造也一样。只有当匹配设计意味着要同时替换消息行、输入框、标题栏和列表时,才选择自定义 UI——也就是说,你只把 SDK 当作数据源,而不使用它的任何 widget。过度选择自定义 UI(手动重建一个更差的即时通信界面,还失去头像/分组/表情反应/话题串/附件/输入状态/回执/选择器)是常见且代价高昂的错误;过度选择组件则只会多花几个小时调整布局。拿不准时,先构建组件版本——这样更快就能确认是否可行。还要把**“直播”/“直播购物”视为信号,而不是标签**:只有在其形态符合条件时(平铺且样式一致的行、叠层/滚动字幕、高流量、只读观众),它们才指向自定义 UI——想要常规气泡/频道列表聊天面板的直播应用仍应使用组件。以上就是完整的决策标准;custom-ui.md 是在决策结果为自定义 UI 后要遵循的构建指南,而不是用于做决定的文档。
Workplace / Slack 风格的混合界面也是组件的工作。 Slack/Teams/Discord 界面由频道列表 + 消息列表 + 撰写框组成,因此仍使用预构建组件 — 但有两点与即时通讯应用不同,必须匹配,而不能跳过:(1)消息行是扁平且左对齐的(头像位于顶部、为圆角方形,标题行包含作者·自定义状态·时间戳,正文、底部反应胶囊和线程回复摘要),没有收发消息气泡的区分 — 通过重写 messageItem 组件构建器来复现(这是一个复合插槽 — 需复现其子特性);(2)标题栏和界面框架是自定义的。完整的 Workplace 原型见 design-matching.md。Workplace 应用也以线程为先,因此要接入线程回复摘要和线程屏幕。
该策略还会选择频道类型和权限模型(例如,社交/市场应用采用受成员资格控制的 messaging,而直播采用公开 + 匿名观众的 livestream)— 参见 RULES.md →“主动说明界面权限前提”,以及步骤 0.5 →“权限意识”。请结合两个维度一起决定。
如果确实不明确,只问一个问题:
这个聊天看起来像标准即时通讯应用(频道列表 + 气泡),还是像直播/叠加层聊天这样的定制界面?这决定了我们是自定义预构建组件,还是基于
stream_chat_flutter_core构建自定义 UI。
消歧流程
如果请求在构建/集成和参考查询之间含糊不清,只问一个简短的问题,然后等待:
你想让我将其接入项目,还是只介绍 Flutter SDK 模式和组件?
分类后
- 轨道 A、B、D -> 每个会话运行一次 Project signals,然后继续阅读
builder.md和sdk.md。如果提出了样式深度标记,则根据 UI 策略决策,同时执行设计匹配阶段 — 对于预构建组件(常见情况),阅读design-matching.md(完整阅读其流程部分 —# Reference分隔线之前的所有内容,可能需要分两次读取),然后按区域 Grep 其参考部分;对于定制的stream_chat_flutter_core界面,阅读custom-ui.md(设计匹配严谨流程是必需阶段,不是可选附加项)。 - 轨道 C -> 如果产品和包已明确,则跳过探查。只有在 SDK 层不明确时,才按需运行探查。
- 轨道 M -> 运行
sendbird-migration.md:检测现有 Sendbird 集成形态,替换包/初始化/视图/频道/消息,通过两个维度重新应用主题,并针对 Sendbird 原版逐屏验证设计和功能一致性。复用步骤 0.5 的凭据以及design-matching.md/custom-ui.md的严谨流程;代码迁移完成后,交接给共享的数据迁移操作手册。
步骤 0.5:凭据、令牌和种子数据(轨道 A、B、D — 以及阶段 M2 的轨道 M)
每个会话运行一次,紧接意图分类之后、Project signals 探查之前。
目标
收集 Stream API key、用户令牌,并可选择预置频道或通话 — 在接触代码之前完成所有这些,以便应用首次运行时就有真实数据可显示。
一次性前置问题(只问一次,然后立即执行)
发送一条消息,一次性询问所有相关事项。不要拆分成多轮。
对于 Chat 项目:
为了使用真实数据完成全部接线,我需要快速确认几个问题:
- 凭据——我应该从控制面板获取你的 API key,并通过 Stream CLI 生成令牌,还是由你自行粘贴?
- 令牌过期时间——如果由我生成令牌:你希望它过期吗?(例如
1h、1d、30m),还是永不过期?- 初始频道——要不要我用随机用户名预先创建几个频道,让应用一开始就有内容可显示?
如果你想自行处理所有事项,只需粘贴你的 API key 和令牌,并告诉我是否要创建初始频道。
对于 Video 项目(通话是临时的——无需预先创建数据):
为了完成全部接线,我需要快速确认几个问题:
- 凭据——我应该从控制面板获取你的 API key,并通过 Stream CLI 生成令牌,还是由你自行粘贴?
- 令牌过期时间——如果由我生成令牌:你希望它过期吗?(例如
1h、1d、30m),还是永不过期?如果你想自行处理所有事项,只需粘贴你的 API key 和令牌。
访客观看者要求——在构建任何以访客身份登录观看者的应用之前,必须先说明这一点。访客以
guest角色连接,该角色默认只有最低限度的能力。在livestream通话类型中,除非集成方为guest角色授予相应能力,否则访客甚至无法读取或加入通话。如果涉及基于访客的观看者流程,请告知集成方:必须先通过 Stream Dashboard → Video & Audio → Call Types → → Roles & Permissions(或使用 API),为相关通话类型的guest角色授予read-call和join-call(如果观看者可能在主持人之前打开通话,还需授予create-call);也可以改用经过身份验证的User.regular观看者。详情请参阅:references/VIDEO-FLUTTER.md→ 访客用户,以及references/LIVESTREAM-FLUTTER.md→ 角色、权限和后台安全。
对于 Feeds 项目(没有预构建的 UI;必须配置 feed groups):
一次性在一条消息中提出所有设置问题——不要分轮询问:
为了完成全部接线,我需要快速确认几个问题:
- 凭据——我应该从控制面板获取你的 API key,并通过 Stream CLI 生成令牌,还是由你自行粘贴?
- 令牌过期时间——如果由我生成令牌:你希望它过期吗?(例如
1h、1d、30m),还是永不过期?- Feed groups——我需要在你的 Stream 项目中创建 3 个 feed groups(user、timeline、notification)。要我自动创建,还是你已经创建好了?
- 初始帖子——要不要我添加几条示例帖子,让 feed 从首次运行开始就有内容?
如果你想自行处理凭据,只需粘贴你的 API key 和令牌。
用户回复后,不要停顿,直接执行所有步骤。对于 feed groups,如果用户说“自动创建”:
getstream api CreateFeedGroup --request '{"id": "user", "type": "flat"}'
getstream api CreateFeedGroup --request '{"id": "timeline", "type": "flat"}'
getstream api CreateFeedGroup --request '{"id": "notification", "type": "notification"}'
如果 CLI 命令失败(Feeds API 使用的端点可能与 Chat 不同),请告知用户一次:
请在 Stream Dashboard → Activity Feeds → Feed Groups 中创建以下 feed groups:
user(Flat)、timeline(Flat)、notification(Notification)。
对于 Feeds 项目,在 connect() 之后的 main 中始终生成两个独立的辅助函数:
_setupFollows(client)——始终无条件调用。使timeline关注user,这样用户自己的帖子就会显示在其中。不要将其合并到初始数据逻辑中——一旦存在初始数据,保护逻辑就会提前返回,关注调用也就永远不会执行。_seedPosts(client)——仅当用户同意创建初始数据时调用。添加示例动态;如果数据已存在则提前退出。
这两个实现请参阅 references/FEEDS-FLUTTER.md。
使用的包是 stream_feeds: ^0.5.1——不要使用已弃用的 stream_feed 或 stream_feed_flutter_core。
用户回复后——无需进一步询问,直接执行
用户回答后,按顺序执行所有 CLI 步骤,中途无需暂停确认。执行时简要说明每个步骤(每个操作一行),但不要停下来询问“要继续吗?”
步骤 A - API 密钥
getstream env --target flutter
这会将公开 API 密钥写入 dart_defines.json;应用通过 String.fromEnvironment('STREAM_API_KEY') 读取该密钥,并使用 flutter run --dart-define-from-file=dart_defines.json 运行。如果命令返回 401 错误,说明 CLI 会话已过期——运行 getstream login 重新进行身份验证,然后重试。
如果未安装 getstream(command not found):请用户从 https://getstream.io 安装,然后等待。或者,如果用户愿意,也可以完全跳过 CLI,让他们粘贴 API 密钥以及每位用户的一个令牌(Dashboard -> Explorer 中有令牌生成器)。根据用户对开头凭据问题的回答来决定;不要停滞不前。
步骤 B - 令牌
# Never-expiring
getstream token <user_id>
# Expiring
getstream token <user_id> --ttl <duration>
将令牌保留在上下文中。在每个代码片段中使用它和 API 密钥,不要使用占位字符串。
步骤 C - 填充频道(仅当用户回答“是”时)
使用随机且真实的用户名创建 3-5 个频道。默认频道类型使用 messaging。
子步骤 C1 — 更新所有用户(填充用户 + 令牌用户):
getstream api UpdateUsers --request '{
"users": {
"<token_user_id>": {"id": "<token_user_id>", "name": "<Display Name>"},
"alice": {"id": "alice", "name": "Alice"},
"bob": {"id": "bob", "name": "Bob"},
"carol": {"id": "carol", "name": "Carol"},
"dave": {"id": "dave", "name": "Dave"}
}
}'
子步骤 C2 — 创建每个频道(请求正文中不包含成员;成员将在 C3 中添加):
getstream api GetOrCreateChannel --type messaging --id <channel-id> \
--request '{"data": {"created_by_id": "<token_user_id>", "custom": {"name": "<Channel Name>"}}}'
为每个频道重复此操作(例如 general、random、team-alpha)。
子步骤 C3 — 使用 add_members 将成员添加到每个频道。 令牌用户必须位于每个频道中,这样应用中的 Filter.in_('members', [userId]) 查询才能返回结果。
getstream api UpdateChannel --type messaging --id <channel-id> \
--request '{
"add_members": [
{"user_id": "<token_user_id>"},
{"user_id": "alice"},
{"user_id": "bob"}
],
"user_id": "<token_user_id>"
}'
生成简短易记的频道 ID(例如 general、random、team-alpha),并使用少量随机用户名(例如 alice、bob、carol、dave)。必须将令牌用户添加到每个频道——频道列表筛选器是 Filter.in_('members', [tokenUserId]),如果该用户不在频道中,就不会返回任何结果。
子步骤 C4 — 填充消息。 使用 message.user_id 在服务端指定发送者。每个频道发送几条消息,以便列表显示预览,且频道页面不会空白;对于要回复的消息,显式设置 message.id,这样线程回复就能引用它,无需解析响应。
getstream api SendMessage --type messaging --id <channel-id> \
--request '{"message":{"id":"<channel-id>-m1","user_id":"alice","text":"Morning - anyone up for a sync today?"}}'
# Threaded reply into that message
getstream api SendMessage --type messaging --id <channel-id> \
--request '{"message":{"user_id":"bob","text":"I will bring the numbers","parent_id":"<channel-id>-m1"}}'
填充完成后,打印简短摘要:
已创建频道:
general(token_user、alice、bob)、random(token_user、carol、dave)、team-alpha(token_user、alice、carol)
步骤 D - 自动继续
所有 CLI 步骤成功后,无需暂停,直接继续——不需要再次询问:Track A/B/D 直接进入 项目信号,然后进入 builder.md;Track M 返回 sendbird-migration.md(阶段 M2)。如果任何 CLI 步骤失败,请简要说明错误,并让用户手动粘贴缺失的值,然后再继续。
不要做的事
- 绝不要将 API 密钥放入应用代码——CLI 仅在服务端使用该密钥。
- 绝不要编造或伪造凭据。
- 在步骤 A、B、C 和 D 之间,绝不要询问“要继续吗?”——收到用户对开头问题的回答后,一次性执行整个流程。
权限须知(Chat - 主动提示)
Stream Chat 会在每次客户端调用时按角色、按范围检查权限,但服务端调用(CLI 和使用 API secret 的后端)会绕过所有检查。这种不对称是“用种子数据初始化时一切正常,但应用返回 403”的首要原因:通过 CLI 创建频道时,无论授权如何都会成功;但应用使用同一查询或加入操作时,会根据已连接用户的角色进行检查并失败。
如果你即将构建的应用会执行超出用户已加入频道内聊天范围的操作,请在编写功能之前告知集成者相关授权要求——不要等到运行时出现 403。 将场景对应到授权项:
| 你要构建的应用行为 | 连接角色在该频道类型上所需的授权项 | user/guest 的默认 messaging 设置 |
|---|---|---|
发现/浏览用户未创建的群组(queryChannels 不带 members 过滤条件) | Read Channel(ReadChannel) | 通常为关闭 |
加入现有群组(channel.addMembers([myId])) | Add Own Channel Membership(AddOwnChannelMembership) | 通常为关闭 |
离开群组(channel.removeMembers([myId])) | Remove Own Channel Membership(RemoveOwnChannelMembership) | 不定 |
| 创建群组 | Create Channel(CreateChannel) | 通常为开启 |
guest 用户(仅名称/无后端登录)的权限限制比 user 更严格——如果应用使用 guest 身份验证,也必须为 guest 角色添加相同的授权项。请引导集成者前往 Dashboard → Chat → Roles & Permissions(permissions v2)配置角色和 messaging 类型,或通过 API/CLI 使用 UpdateChannelType。完整详情和确切的错误消息见:references/CHAT-FLUTTER.md → Channel permissions & roles(自定义 UI 构建:references/CHAT-CORE.md)。
这是一项提示,而非阻碍——按要求构建功能,但要在同一轮中说明前置条件,避免发现/加入/创建操作首次运行时悄然失败。
项目状态信号(轨道 A/B/D/M - 每个会话运行一次;仅按需运行轨道 C)
只读本地探测。用于判断用户是否在 Flutter 项目中,或是否处于空目录。
bash -c 'echo "=== FLUTTER ==="; find . -maxdepth 2 -name "pubspec.yaml" -print 2>/dev/null; echo "=== STREAM ==="; grep -rE "stream_chat|stream_video|stream_feed" . --include="pubspec.yaml" -l 2>/dev/null; echo "=== EMPTY ==="; test -z "$(ls -A 2>/dev/null)" && echo "EMPTY_CWD" || echo "NON_EMPTY"'
将结果保留在对话上下文中。除非用户更改目录或项目结构明显发生变化,否则不要重新运行。
根据结果给出一行状态说明,例如:
Flutter app detected - stream_chat_flutter already in pubspec.yamlFlutter app detected - stream_video_flutter already in pubspec.yamlFlutter app detected - stream_feed already in pubspec.yamlFlutter app detected - no Stream dependency yet, ready to installNo Flutter project found - empty directory
版本前置要求(Chat - 现有项目)
如果项目中已存在 Stream Chat 依赖,请检查解析后的版本(pubspec.yaml 中的约束或 pubspec.lock 中的 version:)。这些技能仅针对 stream_chat_flutter / stream_chat_flutter_core v10。 如果项目固定使用 9.x 或更早版本,请在编辑代码前停止并告知用户:
Your project uses
stream_chat_flutterv. These instructions cover v10. A lot changed between v9 and v10 (widget names, controllers, theming, reaction/delete APIs). The official migration guides are at https://github.com/GetStream/stream-chat-flutter/tree/master/migrations — refer to the relevant version's guide for step-by-step instructions. Once you're on v10, I can continue with the full feature set.
如果用户需要迁移方面的帮助,请从上述 URL 获取相关迁移文档,并逐步指导他们完成迁移。
只有当项目解析到 v10(^10.0.0)依赖时,才继续处理 Chat。新安装始终使用 ^10.0.0,因此此检查仅适用于现有集成。
模块一览
| 轨道 | 模块 |
|---|---|
| A - 新应用 | builder.md + sdk.md + 相关参考文件 |
| B - 现有应用 | builder.md + sdk.md + 相关参考文件 |
| C - 参考资料查询 | sdk.md + 相关参考文件 |
| D - 引导 / 设置 | builder.md + sdk.md |
| M - 从 Sendbird 迁移 | sendbird-migration.md(+ design-matching.md/custom-ui.md、sdk.md、../stream/sendbird-data-migration.md) |
| 样式深度标记(截图/Figma/“看起来像”) | 先选择 UI 策略(步骤 0)。组件 → design-matching.md(完整流程部分——# Reference 分隔符上方的全部内容,可能需要分两次读取;每个区域的参考部分);定制/直播/叠加 → custom-ui.md。在轨道 A/B 的功能开发前执行;无论哪种方式,都要逐区域严谨处理并进行验证 |
Feeds 说明(轨道 A/B): 默认使用 Twitter 风格的 UI。只有用户明确要求其他风格时才偏离(例如“Instagram 网格”“Reddit 风格投票”)。
参考布局
共享的 Flutter/Dart 模式位于 sdk.md。
产品和软件包的具体内容位于 references/ 下,采用扁平命名方案:
- 参考资料:
references/<PRODUCT>-<PACKAGE>.md - 蓝图:
references/<PRODUCT>-<PACKAGE>-blueprints.md
当前已提取的模块:
- 聊天 + 预构建 UI(
stream_chat_flutter):references/CHAT-FLUTTER.md+references/CHAT-FLUTTER-blueprints.md - 聊天 + 自定义 UI(
stream_chat_flutter_core):references/CHAT-CORE.md+references/CHAT-CORE-blueprints.md - 高级聊天(推送、离线、生命周期 — 两种 UI 层级):
references/CHAT-ADVANCED-FLUTTER.md+references/CHAT-ADVANCED-FLUTTER-blueprints.md- 推送通知、离线/本地持久化、连接生命周期与后台运行 - 视频(
stream_video_flutter):references/VIDEO-FLUTTER.md+references/VIDEO-FLUTTER-blueprints.md - 直播(
stream_video_flutter):references/LIVESTREAM-FLUTTER.md+references/LIVESTREAM-FLUTTER-blueprints.md - 视频高级用例(
stream_video_flutter):references/VIDEO-ADVANCED-FLUTTER.md+references/VIDEO-ADVANCED-FLUTTER-blueprints.md- 音频房间、多方通话、聊天+视频、直播动态、查询/事件/偏好设置/审核 - 响铃 / 来电 + 推送(
stream_video_flutter+stream_video_push_notification):references/RINGING-FLUTTER.md+references/RINGING-FLUTTER-blueprints.md- 呼出响铃、前台/后台/已终止状态下的来电、CallKit(iOS)+ FCM(Android) - 动态(
stream_feed/stream_feed_flutter_core):references/FEEDS-FLUTTER.md+references/FEEDS-FLUTTER-blueprints.md
Stream 产品的其他内容应沿用此命名系列,而不是创建更多顶层技能。
Track A - 新建应用
完整详情:builder.md - 使用新项目路径。
| 阶段 | 名称 | 操作 |
|---|---|---|
| A1 | 检测 | 运行项目特征检查。如果尚无 Flutter 应用,请告知用户先运行 flutter create my_app。 |
| A2 | 选择方案 | 确认软件包选择:stream_chat_flutter(预构建 UI,速度最快)、stream_chat_flutter_core(自定义 UI)、stream_video_flutter(视频/直播),或 stream_feed / stream_feed_flutter_core(动态信息流,无预构建 UI)。对于 Chat,这与步骤 0 中“先选择 UI 策略”一样,都是在组件与自定义方案之间做选择——默认优先选择 stream_chat_flutter;只有真正非即时通信类的界面才选择 core(参见custom-ui.md)。对于 Feeds,默认使用 Twitter 风格的 UI。 |
| A3 | 安装并接入 | 按照builder.md + sdk.md 操作,然后仅加载所需的参考文件。 |
| A4 | 验证 | 确认 flutter pub get 成功、客户端已连接,且首个屏幕已渲染。如果应用会发现/加入频道或使用访客身份验证,请再次说明权限前提条件(步骤 0.5 → 权限须知),以免这些流程首次运行时返回 403。 |
Track B - 现有应用
完整详情:builder.md - 使用现有项目路径。
| 阶段 | 名称 | 操作 |
|---|---|---|
| B1 | 检测 | 运行项目特征检查,并在修改前检查现有应用结构。 |
| B2 | 保留 | 除非用户要求更改,否则保留当前的导航、状态管理和组件架构。 |
| B3 | 集成 | 使用sdk.md进行通用接入,然后仅加载所需的参考文件。 |
| B4 | 验证 | 确认所请求的 Stream 流程可以在现有应用中构建并渲染。如果应用会发现/加入频道或使用访客身份验证,请再次说明权限前提条件(步骤 0.5 → 权限须知),以免这些流程首次运行时返回 403。 |
Track C - 参考查询
仅加载所请求软件包的相关文件。
- 共享的生命周期 / 身份验证 / 状态 / 客户端所有权模式 ->
sdk.md - 聊天高级生产环境注意事项——推送通知、离线 / 本地持久化、连接生命周期与后台运行(两个 UI 层级均适用) ->
references/CHAT-ADVANCED-FLUTTER.md - 聊天高级接线蓝图(FCM 设置 + 后台处理程序、持久化初始化、延迟连接门控) ->
references/CHAT-ADVANCED-FLUTTER-blueprints.md - 聊天预构建 UI 设置、组件、主题、成员 / 用户列表、消息搜索、编写器标志(语音 / 投票 / 草稿)、筛选运算符、权限 ->
references/CHAT-FLUTTER.md - 聊天预构建 UI 组件蓝图 ->
references/CHAT-FLUTTER-blueprints.md - 聊天自定义 UI 设置与控制器 ->
references/CHAT-CORE.md - 聊天自定义 UI 组件蓝图 ->
references/CHAT-CORE-blueprints.md - 视频设置、通话类型、控件、状态、StreamCallContainer ->
references/VIDEO-FLUTTER.md - 视频组件蓝图(入口、加入、通话容器、控件、参与者磁贴) ->
references/VIDEO-FLUTTER-blueprints.md - 直播 SDK 模式(通话类型、候播状态、goLive/stopLive、HLS) ->
references/LIVESTREAM-FLUTTER.md - 直播组件蓝图(模式选择、主播、WebRTC 观众、HLS 观众) ->
references/LIVESTREAM-FLUTTER-blueprints.md - 视频高级模式(音频房间、多通话、聊天 + 视频接线、queryCalls、通话事件、偏好设置、审核、会话计时器、网络处理) ->
references/VIDEO-ADVANCED-FLUTTER.md - 视频高级用例蓝图(音频房间屏幕、TikTok 风格直播信息流、浮动通话面板、视频聊天) ->
references/VIDEO-ADVANCED-FLUTTER-blueprints.md - 响铃 SDK 模式(启用推送的初始化、发起呼叫、前台 / 后台 / 终止状态下的来电、CallKit/FCM 设置、接听 / 拒绝 / 结束、自定义、未接来电) ->
references/RINGING-FLUTTER.md - 响铃蓝图(推送初始化、后台 FCM 处理程序、主屏幕观察器、发起呼叫、通话屏幕、iOS AppDelegate、Android manifest/Gradle) ->
references/RINGING-FLUTTER-blueprints.md - 动态信息流 SDK 设置、StreamFeedClient、信息流类型、动态、回应、关注 / 取消关注、实时功能 ->
references/FEEDS-FLUTTER.md - 动态信息流组件蓝图(默认采用 Twitter 风格:主页信息流、动态卡片、发布、个人资料、通知;也提供 Instagram/Reddit 变体) ->
references/FEEDS-FLUTTER-blueprints.md
Track D - 引导 / 设置
当用户更关注安装和接线流程,而非构建功能时使用:
- 判断项目结构
- 选择
stream_chat_flutter或stream_chat_flutter_core - 将 Stream 依赖项添加到
pubspec.yaml,并运行flutter pub get - 通过
sdk.md接入StreamChatClient和StreamChat组件 - 为所选软件包完成平台设置(Android 权限、iOS Info.plist 键)
- 如果用户只要求设置,则在涉及产品特定 UI 之前停止
Track M - 从 Sendbird 迁移
完整详情: sendbird-migration.md。这种迁移以集成为导向
(保留现有应用),因此与 Track B 类似,但采用 Sendbird 专属操作手册。
| 阶段 | 名称 | 操作内容 |
|---|---|---|
| M1 | 检测 | 运行 项目特征;搜索 Sendbird 的使用痕迹,并为每个接触点分类(sendbird-migration.md §0)。记录 Sendbird 基线(§0.5 习惯 0)——进行任何代码更改之前,运行源应用并截取每个由 Sendbird 支持的屏幕/变体(§0 中的接触点,而非整个应用)的截图,包括列表与聊天、传入与传出消息;这些截图就是规格。 |
| M2 | 替换并接线 | 移除 sendbird_chat_sdk/sendbird_uikit,添加 Stream 软件包;获取凭据(步骤 0.5);接入一个 StreamChatClient 和 StreamChat 提供程序,重新指向现有启动流程,但不更改其公共 API(§1–§2)。 |
| M3 | 重新实现 | 按各自模式迁移每个接触点——视图与导航(§3)、频道(§4)、消息/自定义附件(§5);通过两个轴重新应用主题(§6,design-matching.md)。 |
| M4 | 验证 | 将每个区域与基线进行比较,并执行每项交互(§0.5 习惯 2–3 + design-matching.md 步骤 5)——验收标准是完成比较,而不是构建成功。 在原生缩放比例下,将每个区域与其基线截图进行核对(保留路径:视觉上零变化);在设备上执行源应用实际支持的交互(回复/编辑 → 撰写框、选择器、长按、表情回应、线程)——屏幕能显示内容,不代表行为正常。对于任何不匹配之处,都要报告具体阻碍因素(明确且有依据的缺失 SDK API),绝不能默默按 Stream 默认样式交付。确认已彻底移除 Sendbird 依赖。 |
| M5 | 提供数据迁移 | 代码迁移构建成功、连接正常且匹配后,询问是否也要迁移 Sendbird 数据,并交接至 ../stream/sendbird-data-migration.md(§10)。 |