From 8a58cde3ee36d00f8db95ff186add2d01cf8b286 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 13 Sep 2026 22:35:29 +0800 Subject: [PATCH] =?UTF-8?q?docs(ohos):=20=E6=9C=AC=E5=9C=B0=E6=9E=84?= =?UTF-8?q?=E5=BB=BA=E5=89=8D=E7=BD=AE=E6=9D=A1=E4=BB=B6=20+=20=E8=BF=90?= =?UTF-8?q?=E8=A1=8C=E6=97=B6=E9=AA=8C=E8=AF=81=E6=B8=85=E5=8D=95=20+=20?= =?UTF-8?q?=E5=B7=A5=E7=A8=8B=E7=BB=93=E6=9E=84=E8=A1=A8=E5=88=B7=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. **oh_modules 前置条件**:该目录被 .gitignore 忽略但必须存在 —— hvigor 不会 自动 ohpm install,移走后构建直接报 arkts-no-untyped-obj-literals(依赖类型 声明缺失)且不重建目录。写明"clone 后先 ohpm install,别当垃圾清掉", 同时说明 entry/build 与 .hvigor 是纯产物、可随时删(冷构建 ~8s)。 2. **hvigorw 绝对路径**:仓库里的 ./hvigorw 是符号链接,启动脚本按 $(dirname $0) 定位,会报 File not found: /cmd/ohos/hvigor/bin/hvigorw; 统一改用 /bin/hvigorw(本机 /opt/huawei/command-line-tools/bin/hvigorw)。 3. **运行时验证清单**:把"构建通过 ≠ UI 行为不变"这件事写进仓库而不是留在邮件里 (流式对话/思考卡与工具卡/附件上传/设置与设备与插件的二级页/宽屏分栏), 并注明无提权环境起不来模拟器时需在真机补验证。 4. 工程结构表按前几轮拆分后的实际情况刷新(common/components/pages 新增文件与职责), 并记下"单文件 ≤400 行、页面只做壳"的约定。 无代码改动,纯文档。 --- cmd/ohos/README.md | 100 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 78 insertions(+), 22 deletions(-) diff --git a/cmd/ohos/README.md b/cmd/ohos/README.md index 6c5e93c..4d857e8 100644 --- a/cmd/ohos/README.md +++ b/cmd/ohos/README.md @@ -9,30 +9,56 @@ HarmonyOS / OpenHarmony 原生客户端,用 ArkTS + ArkUI 实现(不是 WebV ``` HomeAgent/ ├── AppScope/ 应用级配置与图标 +├── oh_modules/ 依赖(.gitignore 忽略,但**必须存在**,见下节) ├── entry/src/main/ │ ├── ets/ -│ │ ├── common/ 通信与全局状态 -│ │ │ ├── ApiClient.ets REST 客户端(X-API-Key 鉴权、超时、二进制附件) -│ │ │ ├── SseClient.ets SSE 长连接(Last-Event-ID 断线续传) -│ │ │ ├── DeviceBridge.ets 设备桥:把本机能力暴露给 agent -│ │ │ ├── BridgeRouter.ets 桥请求路由 -│ │ │ ├── BridgeCaps.ets 能力声明 -│ │ │ ├── ConnStore.ets 连接配置持久化 -│ │ │ ├── StatusStore.ets 运行状态缓存 -│ │ │ ├── NavBarController.ets / NavStackRegistry.ets 导航 -│ │ │ ├── Constants.ets 主题色板、圆角、超时、分页大小 -│ │ │ └── UserError.ets 错误转人类可读文案 +│ │ ├── common/ 通信、状态与纯逻辑(无 UI) +│ │ │ ├── ApiClient.ets REST 客户端(X-API-Key 鉴权、超时、二进制附件) +│ │ │ ├── SseClient.ets SSE 长连接(Last-Event-ID 断线续传) +│ │ │ ├── ConnStore.ets 连接配置与设备身份持久化 +│ │ │ ├── StatusStore.ets 运行状态缓存(单例 + AppStorage 广播) +│ │ │ ├── Constants.ets 主题色板、圆角、超时、分页大小 +│ │ │ ├── UserError.ets 错误转人类可读文案 +│ │ │ ├── NavBarController.ets / NavStackRegistry.ets 导航栏显隐与导航栈登记 +│ │ │ ├── ChatStore.ets 聊天状态机(消息数组/分页/SSE/防抖刷新,单例) +│ │ │ ├── ChatSse.ets SSE 事件 → 状态翻译(ChatStreamSink 接口) +│ │ │ ├── ChatSession.ets 发送/中断(POST /chat、/chat/file) +│ │ │ ├── ChatHistory.ets 历史载荷与 tool_calls 解析 +│ │ │ ├── ChatFormat.ets ForEach 键、工具卡状态/配色、渠道判定 +│ │ │ ├── AttachmentMeta.ets 附件解析与格式化(纯函数) +│ │ │ ├── AttachmentImage.ets 附件字节获取与解码(沙箱/远端) +│ │ │ ├── DeviceBridge.ets 设备桥客户端(socket 生命周期与命令分发) +│ │ │ ├── BridgeProtocol.ets 设备桥协议消息与帧构造 +│ │ │ ├── BridgeRouter.ets 桥请求路由 +│ │ │ ├── BridgeCaps.ets 能力声明 +│ │ │ ├── DeviceBridgeSession.ets 前台桥生命周期、网关地址推导 +│ │ │ ├── DeviceModel.ets 设备页纯逻辑(device_id 兜底、在线设备解析) +│ │ │ ├── PluginApi.ets 插件列表/详情接口 +│ │ │ ├── PluginStatus.ets 插件状态判定与配色 +│ │ │ ├── SettingsModel.ets 设置载荷解析、分类归并、分页、路由 id +│ │ │ └── MarkdownParser.ets Markdown 解析(块/行内/表格) │ │ ├── components/ 可复用组件 -│ │ │ ├── MarkdownView.ets 流式 Markdown(增量渲染) -│ │ │ ├── StaticMarkdown.ets 静态 Markdown(历史消息,一次成型) -│ │ │ ├── Attachment.ets 附件卡片 + 详情 -│ │ │ ├── StatusCards.ets 状态卡片 -│ │ │ ├── SettingsEditor.ets 配置编辑器 -│ │ │ ├── PageTopBar.ets 顶栏 + 悬浮按钮 -│ │ │ ├── SubPage.ets 二级页容器 +│ │ │ ├── MarkdownView.ets 流式 Markdown(增量渲染) +│ │ │ ├── StaticMarkdown.ets 静态 Markdown(历史消息,一次成型) +│ │ │ ├── Attachment.ets 附件卡 + 附件详情内容 +│ │ │ ├── ChatStream.ets 消息列表 + 顶栏遮罩 + 底部淡出 + 触顶懒加载 +│ │ │ ├── ChatBubble.ets 单条气泡(头像/渠道名/思考卡/工具卡/附件/正文) +│ │ │ ├── ChatToolCard.ets 思考过程卡 + 工具调用卡 +│ │ │ ├── ChatComposer.ets 悬浮输入区(选图/选文件/上传/发送) +│ │ │ ├── ChatAttachBar.ets 加号菜单 + 待发送附件条 +│ │ │ ├── SettingsHome.ets / SettingsRootEntries.ets / SettingsEntryCard.ets 设置一级页 +│ │ │ ├── ConnectionsPane.ets / AppearancePane.ets / BackendSettingsPane.ets 设置二级页 +│ │ │ ├── PluginListView.ets / PluginDetailPane.ets / PluginsOverlays.ets 插件页 +│ │ │ ├── DeviceRootEntries.ets / DevicePanes.ets 设备页 +│ │ │ ├── SettingsEditor.ets 配置编辑器 +│ │ │ ├── StatusCards.ets 状态卡片 +│ │ │ ├── ToastBar.ets 统一提示条(插件页与设置页共用) +│ │ │ ├── PageTopBar.ets 顶栏 + 悬浮按钮 +│ │ │ ├── SubPage.ets 二级页容器 / NavGroup / NavRow / PlainCard +│ │ │ ├── MotionBase.ets 统一按压反馈与入场动画 │ │ │ └── GradientBackground.ets │ │ ├── model/Model.ets 共享类型定义 -│ │ ├── pages/ 页面 +│ │ ├── pages/ 页面(薄壳:导航 + 数据编排) │ │ │ ├── Index.ets Tab 容器(入口) │ │ │ ├── ChatPage.ets 对话 │ │ │ ├── DevicePage.ets 设备 @@ -45,11 +71,22 @@ HomeAgent/ └── oh-package.json5 依赖 ``` +约定:**单个 `.ets` 不超过 400 行**,页面只做页面壳(导航栈 + 数据编排), +可复用结构进 `components/`,无 UI 的逻辑进 `common/`。 + ## 编译 需要 DevEco Studio 或 [command-line-tools](https://developer.huawei.com/consumer/cn/deveco-studio/)。 本工程用 `compatibleSdkVersion 6.1.1(24)` / `compileSdkVersion 26.0.0`。 +0. **前置条件:`oh_modules/` 必须存在**(`ohpm install` 的产物)。 + + 它被 `.gitignore` 忽略,所以干净 clone 后没有;而 hvigor **不会**自动补齐它 —— + 实测把 `oh_modules/` 移走后构建不会触发 `ohpm install`,而是直接报一堆 + `arkts-no-untyped-obj-literals`(依赖类型声明缺失),且不会重建该目录。 + 所以:clone 后先 `ohpm install`,之后别把这个目录当垃圾清掉。 + `entry/build/`、`.hvigor/` 是纯构建产物,可以随时删除(冷构建 ~8s)。 + 1. **准备签名配置**(`build-profile.json5` 含密码明文,未入库): ```bash @@ -64,9 +101,12 @@ HomeAgent/ 2. **构建 HAP**: ```bash - # hvigorw 未入库(本机是符号链接),直接用 command-line-tools 里的 - /path/to/command-line-tools/bin/hvigorw \ - --mode module -p module=entry@default assembleHap --no-daemon + cd cmd/ohos/HomeAgent + # ⚠️ 不要用仓库里的 ./hvigorw:它是符号链接,启动脚本按 $(dirname $0) 定位, + # 会报 File not found: /cmd/ohos/hvigor/bin/hvigorw。 + # 一律用 command-line-tools 里的绝对路径(本机为 /opt/huawei/command-line-tools/bin/hvigorw): + /opt/huawei/command-line-tools/bin/hvigorw \ + assembleHap --mode module -p product=default --no-daemon ``` 产物在 `entry/build/default/outputs/default/entry-default-signed.hap`。 @@ -97,3 +137,19 @@ HomeAgent/ - **修改主题色**:改 `common/Constants.ets` 的 `DARK_PALETTE` / `LIGHT_PALETTE`,全局生效。 - **新增页面**:同时在 `resources/base/profile/main_pages.json` 注册,且只有入口页带 `@Entry`。 - 项目代码部分由 AI 辅助生成,改动请自行评估。 + +## 改动后的运行时验证清单 + +构建通过只能证明编译期没问题;ArkUI 的状态绑定、过渡动画与手势行为 +必须上设备/模拟器点一遍。UI 相关改动(尤其拆分、状态搬家)请至少走完: + +- [ ] 发一条消息,确认流式输出、滚动到底、"AI 思考中/工具调用"状态条正常 +- [ ] 点开思考过程卡与工具调用卡,确认能展开/收起且有过渡动画 +- [ ] 传一张图片与一个文件,确认预览条、上传进度、发送后附件卡正常 +- [ ] 进设置的四个二级页(状态/连接/外观/后端),确认进出场与保存生效 +- [ ] 进插件列表与插件详情,确认状态色、开关与卸载正常 +- [ ] 进出设备页四个二级页,确认授权开关与在线设备列表正常 +- [ ] 宽屏(>=600vp)下确认左右分栏、返回手势与返回键行为 + +模拟器在无图形/无提权环境里可能起不来(需要写 `~/.Huawei` 等宿主目录), +此时请在真机或有权限的机器上补这轮验证,并在提交信息里注明"未做运行时验证"。