docs: 客户端开发交接文档(新机器开工自包含)

客户端开发将转移到另一台机器,本文沉淀本机全部实操经验:
- 环境搭建 + CLI 构建 + 首次自动签名(Account Kit 前置,signingConfigs 现为空)
- AGC 现状:App ID 6917613748100335131 已建、包名核对一致;待办三步
  (自动签名→指纹录入→开 Account Kit 标准登录)
- 后端联调:后端在原开发机 WSL 8666 端口,两种连法(局域网直连/自建);
  DEFAULT_BASE_URL(127.0.0.1:8000) 已过时的说明;dev-token 为主力调试通道
- ArkTS 铁律七条(新增 @Builder 按值传参不随 @State 刷新的 2488 教训)
- hdc/uitest 实测命令与坑(MSYS_NO_PATHCONV、相对路径、dumpLayout 解析法)
- 真机修过的五个坑清单 + 待办任务与开工验收基线
This commit is contained in:
xsl
2026-08-15 22:00:12 +08:00
parent 4125769457
commit 256f850a61
+172
View File
@@ -0,0 +1,172 @@
# 客户端开发交接文档(新机器)
> 创建:2026-08-15 | 用途:**客户端(鸿蒙 FE)开发转移到另一台机器**,本文自包含开工所需的一切。
> 上游文档:`docs/开发任务包/README-FE批次.md`(FE 协作规程与 API 速查)、`docs/本地联调指南.md`(后端起停)、`docs/前置开通清单-云资源与资质.md`(AGC 与外部资源)。
---
## 0. 一句话现状
FE 骨架已完成并通过真机验证的闭环:**dev-token 登录 → 首页配额/对话 → 报告创建(校验/提交/轮询)→ 结果页 32 维渲染 → 40920"本期已生成"对话框**。全部代码在 `main` 分支,直接 clone 即得。
| 仓库 | 地址 | 内容 |
| --- | --- | --- |
| 主仓库 | `https://git.xiangsilian.com/xsl/meida.git` | 文档 + 客户端工程(`app/`) |
| 后端仓库 | `https://git.xiangsilian.com/xsl/meida_backend.git` | FastAPI 后端(原开发机 WSL 运行中) |
---
## 1. 新机器环境搭建
### 1.1 装软件
1. **DevEco Studio**(含 HarmonyOS SDK,API 6.1.1(24))——默认装到 `C:\Program Files\Huawei\DevEco Studio\`
2. 手机开启**开发者模式 + USB 调试**(设置 → 关于 → 连点版本号 → 开发者选项)
### 1.2 拿代码 + 用 DevEco 打开
```bash
git clone https://git.xiangsilian.com/xsl/meida.git
# 用 DevEco 打开 meida/app 工程(File → Open)
```
### 1.3 首次必做:自动签名(Account Kit 的前置)
工程当前 `build-profile.json5` 的 `signingConfigs` 为空(历史包都是 unsigned)。
**DevEco Studio → File → Project Structure → Signing Configs → 勾选 "Automatically generate signature"**,登录华为开发者账号生成调试证书。没做这步,华为账号授权页拉不起来。
### 1.4 CLI 构建(可选,配了 IDE 签名后 CLI 包也会带签名)
```bash
cd <repo>/app
export DEVECO_SDK_HOME="C:/Program Files/Huawei/DevEco Studio/sdk"
"C:/Program Files/Huawei/DevEco Studio/tools/node/node.exe" \
"C:/Program Files/Huawei/DevEco Studio/tools/hvigor/bin/hvigorw.js" \
--mode module -p module=entry@default assembleHap --analyze=false --daemon=false
# BUILD SUCCESSFUL 即通过;产物 app/entry/build/default/outputs/default/
```
路径按新机器实际安装位置调整。"No signingConfigs" WARN 在未配签名时正常。
---
## 2. AGC / 华为侧配置
**已完成**:AGC 应用已创建——**App ID `6917613748100335131`**,包名 `com.xiangsilian.app`(与工程 `app/AppScope/app.json5` 一致)。App ID **不需要**写进代码(Account Kit 靠签名证书+包名识别应用)。
**待办三步**(详见前置开通清单 §1):
| # | 事项 | 位置 |
| --- | --- | --- |
| 1 | 自动签名生成调试证书 | DevEco(§1.3,做完告诉我/记录指纹) |
| 2 | 调试证书 SHA256 指纹录入 AGC | AGC「我的项目 → 应用信息 → 证书指纹」 |
| 3 | 开通 Account Kit(**标准登录**即可,别申请"获取手机号"权限——企业专属,申请必拒) | AGC「我的项目 → 添加服务」 |
个人开发者权限边界:标准登录(UnionID/昵称/头像)✅;一键登录(手机号)❌ 企业专属。我们只需要 UnionID。
---
## 3. 后端联调(重点:后端不在新机器上)
后端跑在**原开发机**的 WSL(Ubuntu-22.04 `/home/xsl/meida_backend`),端口 **8666**(不是 8000)。两种连法:
| 方案 | 做法 | 适用 |
| --- | --- | --- |
| A. 连原机后端 | 新机器与原机同局域网;App 登录页输入 `http://<原机局域网IP>:8666`;原机需后端监听 0.0.0.0 + Windows 防火墙放行 8666 | 最快,推荐 |
| B. 新机器自建后端 | clone `meida_backend`,按 `docs/本地联调指南.md` 起(需 WSL + PG + Redis + .env 密钥) | 需要独立调试后端时 |
**baseUrl 机制**:FE 登录页有"服务器地址"输入框,输一次持久化(preferences)。代码里 `core/AuthStore.ets` 的 `DEFAULT_BASE_URL = 'http://127.0.0.1:8000'` 已过时,**实际一律用登录页输入 8666**;真机别用 127.0.0.1(那是手机自己)。
**联调期登录通道**:`POST /api/v1/auth/dev-token`,请求体 `{"device_key": "<任意字符串>"}`,无需华为/短信——FE 已封装(AuthStore.loginByDevToken),是主力调试通道。
---
## 4. 工程结构与已完成内容
```
app/entry/src/main/ets/
├── core/
│ ├── ApiClient.ets # 信封解析(非200 HTTP 也先验 {code,...} 信封形状再判成败)
│ ├── ApiTypes.ets # ApiError(唯一可抛异常类型)
│ └── AuthStore.ets # 双令牌持久化 + dev-token 登录(postWithoutAuth 通道)
├── pages/
│ ├── LoginPage # 地址输入 + dev-token 登录
│ ├── HomePage # 配额卡片 + 报告入口
│ ├── ChatPage # AI 对话(F4)
│ ├── ReportCreatePage # 问卷六字段 + 校验 + 提交 + 轮询(F3)
│ ├── ReportResultPage # 32 维渲染 + 重新生成(F3)
│ └── ProfilePage / TaskCenterPage(F1/F2)
└── components/f2 f3 f4/ # TaskPollingPanel(任务轮询)、ReportTypes 等公共件
```
路由注册在 `entry/src/main/resources/base/profile/main_pages.json`(新页面必须登记)。
**真机修过的坑(别回退)**:
1. dev-token 登录必须走 `postWithoutAuth`(带鉴权的 post 会因未登录自拦 40100)
2. ApiClient 非 200 HTTP 状态(409/429 等)body 仍是统一信封,先验信封形状再判成败——业务错误 40920/40301/42910 靠这条透传
3. DatePicker 默认折叠成"修改 ▼"(展开态半屏,会把必填项和提交键挤出视野)
4. 轮询成功自动跳转有兜底:"查看报告"按钮 + replaceUrl().catch
5. 表单校验三件套:汇总条点名缺失字段 + 自动滚动到首个错误 + 字段级红字(@Builder $$ 传参,见 §5.7)
---
## 5. ArkTS 严格模式铁律(实测踩坑,违反必炸编译/运行)
1. **泛型调用必须显式类型参数**:`ApiClient.post<void>(...)`——裸 `post(...)` 报 `arkts-no-inferred-generic-params`
2. **请求体用具型 Record 字面量**:`const req: Record<string, Object> = { 'k': v }`;禁止 interface→Record 强转、禁止内联对象类型做泛型参数
3. **wire 响应类型用具名 interface**,字段名对齐后端 JSON
4. **throw 只抛 ApiError**;未知异常包 `new ApiError(50000, '请求失败,请检查网络', '请稍后重试')`
5. **对象字面量必须有具名类型**;async 逻辑放具名方法(箭头链泛型推断受限)
6. `router` 从 `@kit.ArkUI` 导入(`@ohos.router` 编译不过)
7. **@Builder 按值传参不随 @State 刷新**(2026-08-15 新踩):`@Builder f(label: string, err: string)` 的 err 永远停在初始值;必须 `$$` 按引用传参——`@Builder f($$: FieldLabelParams)` + 调用传对象字面量 `{ label: '...', err: this.xxxErr, ... }`
---
## 6. 真机调试工具箱(实测命令与坑)
```bash
HDC="C:/Program Files/Huawei/DevEco Studio/sdk/default/openharmony/toolchains/hdc.exe"
"$HDC" list targets # 看设备
"$HDC" -t <target> shell aa start -a EntryAbility -b com.xiangsilian.app # 拉起 App
cd <产物目录> && "$HDC" -t <t> install -r entry-default-*.hap # 装(本地路径必须相对!绝对路径会被拼错)
# UI 注入(自动化验证主力)
"$HDC" -t <t> shell uitest uiInput click <x> <y>
"$HDC" -t <t> shell uitest uiInput inputText <x> <y> <文本> # 偶发 Invalid parameters 时改用:
"$HDC" -t <t> shell uitest uiInput text <文本> # 输入到已聚焦输入框
"$HDC" -t <t> shell uitest uiInput keyEvent Back # 收键盘
"$HDC" -t <t> shell uitest uiInput swipe <x1> <y1> <x2> <y2> 600 # 滚动=上滑
# 布局dump + 截图(拿坐标/验证UI状态)
MSYS_NO_PATHCONV=1 "$HDC" -t <t> shell uitest dumpLayout -p /data/local/tmp/layout.json
MSYS_NO_PATHCONV=1 "$HDC" -t <t> file recv /data/local/tmp/layout.json layout.json # recv 到当前目录
MSYS_NO_PATHCONV=1 "$HDC" -t <t> shell snapshot_display -f /data/local/tmp/shot.jpeg
```
**坑**:
- Git Bash 会把 `/data/...` 改写成 `C:/Program Files/Git/data/...`——所有带设备路径的命令前加 `MSYS_NO_PATHCONV=1`
- `install` 的本地路径必须 cd 到目录后用相对路径,绝对路径会被 hdc 拼接错
- dumpLayout 是 JSON,用 python 解析 `attributes.bounds`(格式 `[x1,y1][x2,y2]`)取中心点坐标再注入点击
- 键盘没收回时 dump 里会混入输入法节点,先 `keyEvent Back`
---
## 7. 待办任务(优先级序)
| # | 任务 | 前置 | 说明 |
| --- | --- | --- | --- |
| 1 | **FE 华为账号登录接入** | §2 三步完成 | `@kit.AccountKit` 的 AuthorizationButton / createAuthorizationCredential 拿 id_token → `POST /api/v1/auth/huawei`,请求体 `{"id_token": "<JWT>"}`,返回与 dev-token 相同的双令牌结构。后端已就绪(OIDC 验签 + UnionID 映射 `id_user_identity`,`packages/identity/huawei.py` + `apps/api/routers/auth.py:124`) |
| 2 | FE 邮箱验证码登录 UI | 后端 E1(邮箱登录,原机做) | 输入邮箱→发码→验码;接口形态参照原 `/auth/sms/send|verify`(键名以 E1 实现为准) |
| 3 | 真实照片上传 | 后端 E2(本地存储驱动) | 报告页"照片(模拟)"改真实上传;接口以 E2 实现为准 |
| 4 | 已知体验债 | 无 | 轮询完成自动跳转在部分场景仍依赖兜底按钮(@Builder 传函数真机失效的深层原因未根治);AppStorage 重启丢 lastReportId 时 40920 对话框无"查看报告"入口 |
---
## 8. 新机器开工验收基线(先复现,再开发)
1. clone 后 CLI 构建 `BUILD SUCCESSFUL`
2. 自动签名配置成功,装机跑起 App
3. 原机后端 8666 可达(方案 A)→ 登录页输地址 + dev-token 登录成功
4. 走通一次报告流(新用户周期内可完整生成;已生成过则 40920 对话框属正常)