Files
m-stecmd/docs/安卓客户端主框架架构说明.md
阿猫 a976bf525a chore(merge): Update documentation files and file index
- Update Android client architecture documentation
- Update Android client feature specification
- Update Android client development plan
- Refresh file index metadata
2026-09-03 13:48:09 +08:00

139 lines
7.1 KiB
Markdown
Raw Permalink 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.
# 安卓客户端主框架架构说明
> S0 工程骨架交付2026-09-03。本文档说明主框架分层、模块职责、关键约定与业务挂载方法是 S1S4 功能开发的挂载依据。
## 1. 架构总览
```mermaid
flowchart TD
APP[":app 业务壳<br/>导航 · 主题 · 权限 · 配置注入<br/>M1M6 页面挂载点"]
subgraph CORE["core 基础层"]
NET[":core:network<br/>鉴权三要素 · 统一解析"]
DB[":core:database<br/>Room · 上传队列"]
BLE[":core:ble<br/>扫描 · GATT 封装"]
COMMON[":core:common<br/>AppResult · UiState · 日志"]
end
PROTO[":ble-protocol<br/>IE-1000 / VM208 帧解析<br/>纯 Kotlin JVM · 零依赖"]
APP --> NET
APP --> DB
APP --> BLE
APP --> PROTO
NET --> COMMON
DB --> COMMON
BLE --> COMMON
BLE -. "Notify 字节流" .-> PROTO
```
**依赖规则**(静态校验脚本强制核查):
| 规则 | 说明 |
|---|---|
| app → core:* + ble-protocol | 业务壳是唯一允许依赖全部模块的层 |
| core:{network,database,ble} → core:common | core 模块横向互不依赖 |
| ble-protocol 零依赖 | 纯 Kotlin JVM无 Android / 第三方框架依赖 |
| 业务代码禁止绕过 core 层 | S1+ feature 只允许经 core 能力访问网络/存储/蓝牙 |
## 2. 模块职责与关键类
| 模块 | 职责 | 关键类 |
|---|---|---|
| `:app` | 单 Activity 导航壳、5 Tab、权限、配置注入 | `SteCmdApplication` `MainActivity` `FeatureMount` `config/ConfigRepository` |
| `:core:common` | 统一结果/视图状态/日志门面 | `AppResult` `UiState` `AppLog` |
| `:core:network` | 平台 HTTP 框架:鉴权三要素 + 返回码统一解析 | `NetworkConfig` `TokenProvider` `AuthInterceptor` `ApiEnvelope` `ApiError` `NetworkModule` |
| `:core:database` | Room 离线优先存储 + 上传队列参考实现 | `AppDatabase` `UploadQueueEntity` `UploadQueueDao` `DatabaseModule` |
| `:core:ble` | BLE 扫描(名称前缀过滤)与 GATT 连接骨架 | `BleScanner` `BleConnector` `BleSession` `BleUuids` `DeviceType` |
| `:ble-protocol` | 两类设备协议帧解析/编码(独立单测) | `Ie1000FrameParser` `Vm208FrameParser` `Vm208CommandEncoder` `Ie1000Reading` `Vm208Reading` |
## 3. 关键约定
### 3.1 鉴权三要素流(接口文档 1.2
```
ConfigRepository(DataStore+内存快照, app 壳实现 NetworkConfig/TokenProvider)
└→ AuthInterceptor(core:network): 请求头注入 SecretKey / SystemCode / Token
· Token 为空跳过(登录/验证码接口天然不携带)
· 密钥值不进代码库M7-04运行期经 S1 配置页写入 DataStore
```
Hilt 绑定:`config/AppModule.kt``@Binds``ConfigRepository` 绑定为 `NetworkConfig``TokenProvider`,补全 `NetworkModule` 依赖图。
### 3.2 返回码统一解析(接口文档 1.1
| code | 语义 | 异常类型 |
|---|---|---|
| "200" | 成功 | —(`ApiEnvelope.bodyOrThrow()` 返回 data |
| "500" | 业务失败 | `ApiError.ServerError` |
| "429" | 一分钟内同条数据频繁请求超限 | `ApiError.TooManyRequests` |
| "403" | 同条数据连续报错超限(平台锁定) | `ApiError.Locked` |
| 传输层失败 | 超时/断网 | `ApiError.NetworkError` |
code 为**字符串**类型S1+ 业务层只捕获 `ApiError` 并按子类提示。
### 3.3 协议解析流BLE Notify → 上传队列)
```
BleSession.notifyBytes(ByteArray 流)
└→ Ie1000FrameParser / Vm208FrameParser.feed(bytes) ← 内部缓冲,天然处理粘包/残包
└→ Ie1000Reading / Vm208Reading
└→ 组装上传 JSON → UploadQueueDao.enqueue() ← 离线优先,网络可用后补传
```
- IE-1000`'Y' + 4B float(压力,小端) + 'T' + 4B float(温度) + 0D0A`12 字节定长;
- VM208`CC F原值 T原值 E原值 S质量 AA + 0D0A`,缩放 /10 /10 /100
- VM208 激励命令:`0F 0F 06 0A XX XX 0D 0A`(大端 16 位),`Vm208CommandEncoder`
- ⚠ VM208 服务 UUID 原文档仅 31 位十六进制,`BleUuids` 按末位补 0 占位,**S2 真机联调时用 nRF Connect 校准**。
### 3.4 网络安全白名单
`app/src/main/res/xml/network_security_config.xml`:默认全域禁明文;仅接口文档 1.2.4 测试 IP `106.15.183.20` 开放 cleartext联调用发布前如生产全 HTTPS 可移除该 domain-config
## 4. 业务挂载指南S1 挂载步骤)
挂载机制:`FeatureMount.mounts` 注册表声明每个 Tab 的 Fragment 类;导航壳只认注册表,业务页替换注册项即可。
以 S1 首页M2 项目列表)为例:
1. **建 Fragment**`app/src/main/kotlin/com/stec/cmd/feature/home/HomeFragment.kt``@AndroidEntryPoint` + ViewBinding或迁移至团队选定的 UI 方案);
2. **建 ViewModel**`HomeViewModel`,注入 S1 新建的 Retrofit Service声明在 core:network 或独立 feature 模块);
3. **换注册项**`FeatureMount.mounts``Tab.HOME``fragmentClass``HomeFragment::class.java`(占位)改为业务 Fragment
4. **加接口**Retrofit Service 方法返回 `ApiEnvelope<T>`,调用侧 `bodyOrThrow()` 拿业务数据、捕获 `ApiError`
5. **跑校验**`./gradlew :app:assembleDebug`,并确认静态校验脚本(见 §6通过menu↔FeatureMount id 对应关系不受影响)。
M1我的额外步骤配置页 UI 读写 `ConfigRepository.updateConnection()/updateToken()`M1-06
## 5. 目录结构对照
```
SteCmdAndroid/
├─ app/ # 业务壳(本表 §2 :app
├─ core/
│ ├─ common/ # AppResult / UiState / AppLog
│ ├─ network/ # AuthInterceptor / ApiEnvelope / ApiError / NetworkModule
│ ├─ database/ # AppDatabase / UploadQueue 实体与 DAO / DatabaseModule
│ └─ ble/ # BleScanner / BleConnector / BleSession / BleUuids / DeviceType
├─ ble-protocol/ # 协议解析src/main + src/test 冒烟单测)
├─ gradle/
│ └─ libs.versions.toml # 版本目录:全工程唯一版本事实源
├─ docs/ # 规划文档、协议原文、本说明
├─ settings.gradle.kts # 6 模块注册
└─ build.gradle.kts # 根插件版本声明apply false
```
## 6. 环境与验证
| 场景 | 命令 / 操作 |
|---|---|
| 首次打开 | Android StudioJDK 17打开工程根目录等待 Gradle Sync |
| 编译 | `./gradlew :app:assembleDebug` |
| 协议单测 | `./gradlew :ble-protocol:test` |
| 静态校验(本机已通过 198 项) | `python3 /tmp/verify_core.py && python3 /tmp/verify_app.py`(脚本随会话生成) |
| 真机联调 | 配置页写入三要素 + 测试地址后先验证登录M1-01 |
## 7. 已知遗留S1 前处理)
1. Gradle Sync / 编译 / 单测**尚未在真实环境执行**(交付环境无 JDK/Android SDK
2. VM208 服务 UUID 需真机校准§3.3
3. splash 与导航图标为几何占位S6 发布前替换正式视觉;
4. 密钥SecretKey/SystemCode首次运行需经配置页写入协议文档附带密钥文件仅用于联调不得入库。