Files
harmony-client/docs/architecture.md

210 lines
8.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# HarmonyOS NEXT 客户端 · 架构设计文档
> 项目:`harmony-client`(ArkTS + ArkUI,SDK 6.0.2 / API 22,仅 phone)
> 业务形态:对接自有后端的通用业务客户端(HTTP + 鉴权 + CRUD)
---
## 1. 背景与目标
本工程从 DevEco 空脚手架起步,目标是建立一套**可持续演进、可测试、低耦合**的客户端架构骨架,为后续业务开发打底。设计依据来自一轮 deep-research 调研(交叉验证华为官方文档与社区实践,9 条结论全部通过对抗式验证)。
核心决策:
| 决策点 | 选择 | 理由 |
|---|---|---|
| 工程结构 | 官方三层 commons / features / products | 单向依赖、官方白皮书推荐 |
| 模块化 | **单 HAP + 多 HAR** | HAR 编译期打包、可裁剪;HSP 仅按需加载 |
| 代码分层 | **MVVM + 独立 data 层** | 官方指南 + 网络/数据解耦 |
| 状态管理 | **全量 StateManagement V2** | API 22 下 V2 能力完整,字段级精准刷新 |
---
## 2. 模块划分与依赖
```
harmony-client/
├── entry/ HAP 应用壳 + 业务功能(唯一入口,EntryAbility)
├── common/ HAR 基础设施层(网络 / 日志 / 状态 / 工具,无业务、无 UI 组件)
└── uikit/ HAR 通用 UI 组件库 + 主题(无业务、无网络依赖)
```
依赖方向严格单向,禁止反向/循环:
```
entry ──依赖──▶ common
entry ──依赖──▶ uikit
common / uikit 各自独立,互不依赖
```
- **common**:`HttpClient`、鉴权拦截器、统一错误模型、`Logger`、`SessionStore`(PersistenceV2 持久化)、工具函数。
- **uikit**:主题 token(`AppColor/AppSpacing/AppFontSize`)、通用组件(`AppButton/LoadingView/EmptyView`)。
- **entry**:应用壳装配、路由、DI 容器、MVVM 分层业务代码。
---
## 3. 分层与目录结构(entry 内)
采用官方 MVVM 指南的**层优先**结构,叠加独立 `data/` 层与横切的 `router/`、`di/`:
```
entry/src/main/ets/
├── entryability/
│ └── EntryAbility.ets # 生命周期装配:Logger / ServiceLocator / SessionStore
├── router/
│ ├── RouteMap.ets # 路由名常量 + name→页面 分发
│ └── AppRouter.ets # Navigation 导航封装(push/replace/pop/...)
├── di/
│ └── ServiceLocator.ets # 轻量服务定位器(ArkTS 无反射,手动注册/解析)
├── model/ # 领域模型:@ObservedV2 + @Trace 实体
├── data/
│ ├── api/ # DTO + 请求服务(调 common 的 HttpClient)
│ └── repository/ # 数据仓库契约(抽象类)+ 实现
├── viewmodel/ # @ObservedV2 状态容器(data/loading/error 三态)
├── view/ # 可复用 UI 组件(@ComponentV2)
└── pages/ # 页面,仅编排(组合 view + viewmodel)
```
**单向数据流**:
```
pages → viewmodel → repository(契约) → api → HttpClient → 后端
↑ 状态回传由 @Trace 触发自动刷新
```
---
## 4. 状态管理约定(全量 V2,禁用 V1)
| 场景 | 使用 |
|---|---|
| 组件/页面 | `@ComponentV2` |
| 组件内部状态 | `@Local` |
| 父→子输入 | `@Param` |
| 子→父输出/回调 | `@Event`(**不用 `@Link`**;需双向时用 `@Param` 的 `!!` 语法糖) |
| 类/模型可观察 | `@ObservedV2` 类 + `@Trace` 字段 |
| 跨层共享 | `@Provider` / `@Consumer` |
| 变化监听 | `@Monitor` |
| 全局会话 | `SessionStore`(`@ObservedV2` 单例,见 `common/state/SessionStore.ets`) |
| 轻量持久化 | `PersistenceV2.globalConnect(...)`;结构化数据后续用 relationalStore(RDB) |
**核心约定**:ViewModel 是 `@ObservedV2` 类,持有 `@Trace` 的 `data/loading/error` 三态;页面只读状态、调方法,不直接碰 Repository / 网络层。
---
## 5. 网络与数据层
### 5.1 网络层(`common/src/main/ets/network/`)
- `HttpClient`:封装 `@kit.NetworkKit` 的 http,统一超时/请求头,支持**拦截器链**。
- `HttpInterceptor`:拦截器接口(`onRequest` / `onResponse`)。
- `AuthInterceptor`:请求前注入 `Authorization: Bearer <token>`;401 时清空会话。
### 5.2 鉴权流程
```
请求 → AuthInterceptor.onRequest 注入 token → 发出
→ AuthInterceptor.onResponse 检查 401
→ (当前) 清空 SessionStore,由上层跳登录
→ (TODO) token 刷新 + 原请求重放(防并发刷新),需后端 refresh 接口约定后实现
```
### 5.3 Repository 模式
- `data/repository/` 中定义**抽象类契约**,ViewModel 只依赖契约,实现可替换(真实 / mock)。
- 用抽象类而非 interface,是为了在 `ServiceLocator` 中做 `Object → 契约` 强转时兼容 ArkTS。
- `data/api/` 返回 DTO,Repository 负责 **DTO → 领域模型** 映射。
### 5.4 统一响应与错误
- `ApiResult<T>`:`{ code, message, data }`,`code === 0` 为成功。
- `ApiError`:区分网络异常 / HTTP 状态码 / 业务错误码。
---
## 6. 横切关注点
### 6.1 依赖注入
`di/ServiceLocator.ets`:`Map<string, Object>` 单例注册表。启动时在 `EntryAbility.onCreate` 注册 `HttpClient`、各 Repository、`SessionStore`;业务侧 `get(key)` 后强转。
> ArkTS 无反射,用字符串 key + 显式强转;若后续规模增大可引入类型安全的 key 常量或轻量注入容器。
### 6.2 导航
`Navigation` + `NavPathStack`(官方推荐,替代旧 Router)。`RouteMap.ets` 定义路由名常量与 `name→页面` 分发;`AppRouter` 持有全局 `NavPathStack` 提供 `push/replace/pop/popToName/clear`。HAR 不承载路由。
### 6.3 日志
`common/logging/Logger.ets`:封装 `hilog`,统一 DOMAIN,后续可加等级开关/上报。
### 6.4 持久化
- `PersistenceV2`:轻量 KV(token / 用户偏好),`@Trace` 字段自动落盘。
- `relationalStore(RDB)`:结构化数据(订单、列表缓存等),后续引入。
---
## 7. 编码规范
1. **状态管理只用 V2**:新组件一律 `@ComponentV2`,禁止混入 V1 装饰器。
2. **单向数据流**:父→子用 `@Param`,子→父用 `@Event`;页面不直接改 ViewModel 之外的全局状态。
3. **页面只编排**:`pages/` 下只做组件组合与 ViewModel 调用,业务逻辑进 ViewModel,数据进 Repository/Api。
4. **跨模块引用走 `Index.ets`**:entry 只 `import { ... } from 'common'/'uikit'`,不直接引 HAR 内部路径。
5. **魔法值收敛到 `uikit/theme/Theme.ets`**:颜色/间距/字号统一取 token。
---
## 8. 演进指南
### 8.1 抽取 feature HAR(业务领域明确后)
当某个业务领域(如订单、支付)足够独立时,新增 `feature_xxx` HAR:
```
feature_order/
├── src/main/ets/{model,data,viewmodel,view,pages}
└── oh-package.json5 (name: feature_order, main: Index.ets)
```
- 根 `build-profile.json5` 的 `modules` 增加该模块。
- 依赖它的模块在其 `oh-package.json5` 增加 `"feature_order": "file:../feature_order"`。
- 依赖方向:`entry → feature_xxx → common/uikit`,禁止 feature 之间横向依赖(确实需共享时下沉到 `common`)。
### 8.2 迁移到 feature-first
当 feature 数量增多、单层目录过深时,可将 `model/data/viewmodel/view/pages` 按 feature 重组:
```
ets/features/<feature>/{model,data,viewmodel,view,pages}
ets/shared/… # 跨 feature 共享
```
迁移原则:先把稳定边界抽 HAR,再在 HAR 内部做 feature 分组。
---
## 9. 调研结论摘要与引用
- 官方 MVVM(StateManagement V2)指南给出 `model/viewmodel/view/pages` 分层。
- 官方三层工程结构:commons(禁止反向依赖)/ features / products(不可横向调用),打包形态 HAR/HSP/Feature HAP/Entry HAP。
- V2 装饰器映射:`@State→@Local`、`@Prop→@Param`、`@Link→@Param+@Event`、`@Observed→@ObservedV2+@Trace`、`@Watch→@Monitor`、`AppStorage→AppStorageV2`、`PersistentStorage→PersistenceV2`。
- V1/V2 不可混用(编译错误);API 19+ 提供 `UIUtils.enableV2Compatibility/makeV1Observed` 放宽混合约束。
主要引用:
- https://developer.huawei.com/consumer/en/doc/harmonyos-guides/arkts-mvvm-v2
- https://developer.huawei.com/consumer/cn/doc/HarmonyOS-Guides/arkts-decorator-overview
- https://device.harmonyos.com/en/docs/apiref/harmonyos-guides/arkts-v1-v2-update-difference
- https://github.com/openharmony/docs(arkts-v1-v2-migration-application / mixusage / inner-component)
- https://github.com/OpeNopEn2007/arkts-patterns
---
## 10. 边界与后续
- 本次为**骨架级**交付,未实现真实后端对接与具体业务(保留示例链路)。
- 未新增 feature HAR(无业务领域),仅写入抽取指南。
- 未做多设备适配(已确认仅 phone)。
- 后续待办:token 刷新策略、RDB 持久化、自动化测试基建、环境配置注入(BASE_URL)。