docs: align product scope with LAN ABSDK access
This commit is contained in:
+64
-32
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## 1. 文档范围
|
## 1. 文档范围
|
||||||
|
|
||||||
本文记录第一轮工程基础已经建立的模块边界、依赖方向和并行开发接口。ABSDK 0630 的初始化、协议、签名、连接重定向和会话清理等未确认内容不在本文中固化。
|
本文记录已建立的模块边界、依赖方向、提供方路由和并行开发接口,覆盖 ABox(局域网 ABSDK)与本地体验两条连接路径。ABSDK 0630 的初始化、签名细节和会话清理等未确认内容不在本文中固化,协议观测证据见 `docs/protocol/absdk-0630.md`。
|
||||||
|
|
||||||
产品范围和固定分工以 `docs/project_plan.md` 为准,原始简要需求继续保留在 `docs/requirement_spec.md`。
|
产品范围和固定分工以 `docs/project_plan.md` 为准,原始简要需求继续保留在 `docs/requirement_spec.md`。
|
||||||
|
|
||||||
@@ -11,10 +11,14 @@
|
|||||||
```text
|
```text
|
||||||
abox-mgr/
|
abox-mgr/
|
||||||
├── android/
|
├── android/
|
||||||
│ ├── app/ # Android 应用与依赖注入组合根
|
│ ├── app/ # Android 应用、提供方路由与依赖注入组合根
|
||||||
│ └── core/designsystem/ # Compose Material 3 设计系统基础
|
│ └── core/
|
||||||
|
│ ├── designsystem/ # Compose Material 3 设计系统基础
|
||||||
|
│ └── session/ # 提供方 profile、凭据 Keystore 持久化
|
||||||
├── domain/ # 纯 Kotlin 领域模型和公共端口
|
├── domain/ # 纯 Kotlin 领域模型和公共端口
|
||||||
├── testing/fakes/ # 确定性的公共 Fake
|
├── absdk-bridge/ # ABSDK 0630 防腐层(生产)
|
||||||
|
├── runtime/simulation/ # 本地体验模拟运行时(生产)
|
||||||
|
├── testing/fakes/ # 测试专用 Fake(仅测试依赖)
|
||||||
├── docs/
|
├── docs/
|
||||||
└── samples/ # 历史示例,仅供参考
|
└── samples/ # 历史示例,仅供参考
|
||||||
```
|
```
|
||||||
@@ -23,10 +27,13 @@ abox-mgr/
|
|||||||
|
|
||||||
```text
|
```text
|
||||||
android/app ────────────────┬──> android/core/designsystem
|
android/app ────────────────┬──> android/core/designsystem
|
||||||
|
├──> android/core/session ──> domain
|
||||||
├──> domain
|
├──> domain
|
||||||
└──> testing/fakes ──> domain
|
├──> absdk-bridge ──> domain
|
||||||
|
└──> runtime/simulation ──> domain
|
||||||
|
|
||||||
android/core/designsystem ─────> Compose Material 3
|
android/core/designsystem ─────> Compose Material 3
|
||||||
|
testing/fakes(仅测试)────────> domain
|
||||||
domain ────────────────────────> Kotlin 与 Coroutines
|
domain ────────────────────────> Kotlin 与 Coroutines
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -34,21 +41,29 @@ domain ────────────────────────>
|
|||||||
|
|
||||||
## 3. 提供方与数据隔离
|
## 3. 提供方与数据隔离
|
||||||
|
|
||||||
应用计划支持 ABox、自有兼容后端和本地体验三种提供方。每个连接配置由 `ProviderProfileId` 标识,所有会话、设备目录和设备操作都显式携带该标识。
|
认证前应用只提供两种入口,两者在所有构建变体中始终可用:
|
||||||
|
|
||||||
|
1. **ABox**:通过进程内唯一的真实 `AbsdkBridge` 连接当前局域网中的智能家居网关,登录成功后进入应用;
|
||||||
|
2. **本地体验**:由 `:runtime:simulation` 直接建立模拟会话并进入应用,不请求凭据、不访问网络、不调用 ABSDK。
|
||||||
|
|
||||||
|
每个提供方 profile 由 `ProviderProfileId` 标识,所有会话、设备目录和设备操作都显式携带该标识。
|
||||||
|
|
||||||
约束:
|
约束:
|
||||||
|
|
||||||
- 任一时刻只启用一个提供方;
|
- 任一时刻只启用一个提供方;
|
||||||
- 切换远端提供方前必须退出当前会话;
|
- 切换提供方前必须退出当前会话;
|
||||||
- 不同连接配置的数据、凭据和设备状态不得互相混用;
|
- 不同提供方的数据、凭据和设备状态不得互相混用;
|
||||||
- 本地体验不调用 ABSDK,也不启动本地 HTTP 服务;
|
- 本地体验不调用 ABSDK,也不启动本地 HTTP 服务;
|
||||||
- Fake 使用相同标识隔离规则,便于在没有真实环境时验证边界。
|
- Release 不是特殊情况:debug 与 release 暴露相同的提供方和路由行为。
|
||||||
|
|
||||||
## 4. 公共领域端口
|
## 4. 公共领域端口
|
||||||
|
|
||||||
`domain` 当前提供以下最小端口:
|
`domain` 当前提供以下最小端口:
|
||||||
|
|
||||||
- `SessionGateway`:登录、观察会话、验证会话和退出;
|
- `SessionGateway`:登录、观察会话、验证会话和退出;
|
||||||
|
- `LocalSessionGateway`:无凭据本地会话的标记端口,继承 `SessionGateway`;
|
||||||
|
- `ProviderProfileStore`:提供方 profile、活动 profile 和登录偏好持久化;
|
||||||
|
- `CredentialStore`:自动登录凭据的加密存取;
|
||||||
- `DeviceCatalog`:按提供方观察设备目录;
|
- `DeviceCatalog`:按提供方观察设备目录;
|
||||||
- `SocketGateway`:查询和设置插座状态;
|
- `SocketGateway`:查询和设置插座状态;
|
||||||
- `TemperatureHumidityGateway`:读取温度和湿度;
|
- `TemperatureHumidityGateway`:读取温度和湿度;
|
||||||
@@ -63,9 +78,9 @@ domain ────────────────────────>
|
|||||||
- `Success<T>` 携带类型化领域值;
|
- `Success<T>` 携带类型化领域值;
|
||||||
- `Failure` 携带 `DomainError`;
|
- `Failure` 携带 `DomainError`;
|
||||||
- `DomainError.externalCode` 可以保留外部 SDK 错误码用于诊断;
|
- `DomainError.externalCode` 可以保留外部 SDK 错误码用于诊断;
|
||||||
- UI 不接触 `ABRet`、原始 `Map`、HTTP 表单或服务端数据库模型。
|
- UI 不接触 `ABRet`、原始 `Map`、HTTP 表单或任何服务端数据库模型。
|
||||||
|
|
||||||
真实 ABSDK 适配层必须在后续 `feat/absdk-bridge` 分支中完成同步阻塞调用的后台串行化、返回解析和错误映射。
|
ABSDK 防腐层已在 `:absdk-bridge` 中完成同步阻塞调用的后台串行化、返回解析和错误映射。
|
||||||
|
|
||||||
## 6. Fake 边界
|
## 6. Fake 边界
|
||||||
|
|
||||||
@@ -77,58 +92,75 @@ domain ────────────────────────>
|
|||||||
- 记录红外学习、发送和下载调用;
|
- 记录红外学习、发送和下载调用;
|
||||||
- 可直接用于其他模块的 ViewModel 与 UI 测试。
|
- 可直接用于其他模块的 ViewModel 与 UI 测试。
|
||||||
|
|
||||||
Fake 只用于开发和测试,不能作为真实 ABox 或真实硬件验收证据。
|
Fake 只用于开发和测试,不能作为真实 ABox 或真实硬件验收证据。`:testing:fakes` 是测试专用模块,不得加入应用生产依赖。
|
||||||
|
|
||||||
## 7. Android 组合根
|
一个例外是 `FakeDeviceCatalog`:ABSDK 不提供设备目录,而提供方作用域的生产 ABox 设备目录由设备目录模块负责,尚未落地。在该模块交付前,debug 构建的组合根暂时用 `FakeDeviceCatalog` 充当 ABox 目录占位。这是一个临时的目录所有权边界:不得把 ABox 目录请求路由到本地体验的模拟目录,release 构建在出现真实消费方之前不声明 `DeviceCatalog` 绑定。
|
||||||
|
|
||||||
|
## 7. 本地体验模拟运行时
|
||||||
|
|
||||||
|
`:runtime:simulation` 是生产 Kotlin/JVM 模块,为本地体验提供确定性实现:
|
||||||
|
|
||||||
|
- `SimulationSessionGateway`:直接建立无凭据的本地会话;
|
||||||
|
- `SimulationDeviceCatalog`:内置的本地体验设备目录;
|
||||||
|
- `SimulationSocketGateway`、`SimulationTemperatureHumidityGateway`、`SimulationInfraredGateway`:固定行为的模拟设备操作。
|
||||||
|
|
||||||
|
模拟实现不暴露脚本化失败注入、调用记录或断言辅助;这些能力只存在于 `:testing:fakes`。
|
||||||
|
|
||||||
|
## 8. Android 组合根与提供方路由
|
||||||
|
|
||||||
`android/app` 是单 Activity Compose 应用,负责:
|
`android/app` 是单 Activity Compose 应用,负责:
|
||||||
|
|
||||||
- `ABoxManagerApplication` 与 Hilt 组合根;
|
- `ABoxManagerApplication` 与 Hilt 组合根;
|
||||||
- `MainActivity`;
|
- `MainActivity`;
|
||||||
- 根 `NavHost`;
|
- 根 `NavHost` 与提供方选择、登录、认证后路由;
|
||||||
- 仅在 debug 构建中将领域端口绑定到当前开发阶段的 Fake,release 构建不包含 Fake;
|
|
||||||
- 默认英文和简体中文资源;
|
- 默认英文和简体中文资源;
|
||||||
- 使用 `android/core/designsystem` 的主题和基础组件。
|
- 使用 `android/core/designsystem` 的主题和基础组件。
|
||||||
|
|
||||||
|
组合根按端口绑定生产实现:
|
||||||
|
|
||||||
|
```text
|
||||||
|
SessionGateway -> AbsdkBridge(进程内单例)
|
||||||
|
LocalSessionGateway -> SimulationSessionGateway
|
||||||
|
SocketGateway -> RoutingSocketGateway
|
||||||
|
TemperatureHumidityGateway -> RoutingTemperatureHumidityGateway
|
||||||
|
InfraredGateway -> RoutingInfraredGateway
|
||||||
|
```
|
||||||
|
|
||||||
|
`AbsdkBridge` 以 Hilt 单例提供并在所有构建变体中相同:会话与插座/温湿度/红外操作共享同一个 Bridge 实例,使互斥锁和 Bridge 本地会话与厂商 SDK 单例状态保持一致。三个 Routing 网关读取活动 profile 并按提供方分发——ABox 转发到共享的 AbsdkBridge 实现,本地体验转发到模拟实现。任何功能 UI 都不直接选择真实或 Fake 实现。
|
||||||
|
|
||||||
设备目录导航、插座与温湿度页面、红外页面和情景页面由固定模块负责人实现,不放入工程基础层。
|
设备目录导航、插座与温湿度页面、红外页面和情景页面由固定模块负责人实现,不放入工程基础层。
|
||||||
|
|
||||||
## 8. ABSDK Bridge
|
## 9. ABSDK Bridge
|
||||||
|
|
||||||
`:absdk-bridge` 是纯 Kotlin/JVM 防腐层,依赖 `domain` 并实现会话、插座、温湿度和红外 Gateway。该模块:
|
`:absdk-bridge` 是纯 Kotlin/JVM 防腐层,依赖 `domain` 并实现会话、插座、温湿度和红外 Gateway。该模块:
|
||||||
|
|
||||||
- 只在 `VendorAbsdkClient` 中接触 `ABSDK`、`ABRet` 和 `IrInfo`;
|
- 只在 `VendorAbsdkClient` 中接触 `ABSDK`、`ABRet` 和 `IrInfo`;
|
||||||
- 将所有同步调用移到后台并串行进入全局 SDK;
|
- 将所有同步调用移到后台并串行进入全局 SDK;
|
||||||
- 将返回值和错误码转换为 `DomainResult` 和领域模型;
|
- 将返回值和错误码转换为 `DomainResult` 和领域模型;
|
||||||
- 不提供设备目录;
|
|
||||||
- 不调用未确认的 `setHostInfo`;
|
- 不调用未确认的 `setHostInfo`;
|
||||||
- logout 只清除 Bridge 本地会话,因为 JAR 没有公开 logout 或 Token setter;
|
- logout 只清除 Bridge 本地会话,因为 JAR 没有公开 logout 或 Token setter;
|
||||||
- 生产工厂始终返回进程内同一个 Bridge,使互斥锁和本地会话与厂商单例保持一致;
|
- 生产工厂始终返回进程内同一个 Bridge,使互斥锁和本地会话与厂商单例保持一致;
|
||||||
- 真实工厂标记为 `@CleartextAbsdkTransport`,调用方必须显式 opt-in 承认厂商 JAR 的硬编码 HTTP 风险;
|
- 真实工厂标记为 `@CleartextAbsdkTransport`,调用方必须显式 opt-in 承认厂商 JAR 的硬编码 HTTP 风险;
|
||||||
- 当前直接引用归档 Sample 目录中的唯一一份 JAR,不复制厂商二进制。
|
- 当前直接引用归档 Sample 目录中的唯一一份 JAR,不复制厂商二进制;
|
||||||
|
- ABSDK 0630 没有设备目录能力,Bridge 因此也不提供设备目录或设备发现。
|
||||||
|
|
||||||
Bridge 本轮尚未加入 `android/app` 依赖,App debug 仍绑定 Fake。提供方选择、安全凭据和真实 Bridge 绑定由后续 `feat/provider-login` 完成;在获批的传输控制方案明确前,不得在 App 中启用真实 Bridge。协议证据与限制记录在 `docs/protocol/absdk-0630.md`。
|
App 组合根已通过 Hilt 单例绑定该 Bridge,绑定处以 `@CleartextAbsdkTransport` 显式 opt-in 承认厂商 JAR 的硬编码明文 HTTP 风险;App 同时声明 `INTERNET` 权限并允许明文传输(`usesCleartextTraffic`),这是项目所有者对当前局域网集成约束的明确风险接受,不代表传输具备机密性或完整性。协议证据与限制记录在 `docs/protocol/absdk-0630.md`。
|
||||||
|
|
||||||
## 9. Provider Session
|
## 10. Provider Session
|
||||||
|
|
||||||
`:android:core:session` 负责提供方登录的持久化与 Android 安全边界:
|
`:android:core:session` 负责提供方登录的持久化与 Android 安全边界:
|
||||||
|
|
||||||
- `ProviderProfileStore` 使用 DataStore 保存 profile、当前活动 profile、记住用户名和自动登录开关;
|
- `ProviderProfileStore` 使用 DataStore 保存 profile、当前活动 profile、记住用户名和自动登录开关;已移除的提供方类型(如历史兼容后端值)被忽略,不会成为活动 profile;
|
||||||
- `CredentialStore` 使用 Android Keystore 中的 AES-256-GCM 密钥加密自动登录凭据,DataStore 只保存带随机 IV 的密文;
|
- `CredentialStore` 使用 Android Keystore 中的 AES-256-GCM 密钥加密自动登录凭据,DataStore 只保存带随机 IV 的密文;
|
||||||
- `ProviderProfileId` 作为 GCM AAD,防止不同 profile 的密文互换;
|
- `ProviderProfileId` 作为 GCM AAD,防止不同 profile 的密文互换;
|
||||||
- `LocalSessionGateway` 只维护本地内存 Session,不调用 HTTP 或 ABSDK;
|
- 本地体验的会话由 `:runtime:simulation` 的 `SimulationSessionGateway` 提供,不调用 HTTP 或 ABSDK。
|
||||||
- `UnavailableRemoteSessionGateway` 在远端入口未获批准时明确拒绝登录。
|
|
||||||
|
|
||||||
纯 Kotlin `SessionCoordinator` 统一处理启动恢复、提供方选择、登录偏好、自动登录、Token 失效重登、退出和切换提供方。远端退出清除密码和 Session,但保留 profile 与 remembered username;本地体验退出后回到提供方选择。
|
纯 Kotlin `SessionCoordinator` 统一处理启动恢复、提供方选择、登录偏好、自动登录、Token 失效重登、退出和切换提供方。ABox 登录成功必须来自注入的真实 Bridge 返回 `DomainResult.Success<Session>`;无效凭据和网络错误停留在登录页并显示本地化错误。ABox 远端退出清除密码和 Session,但保留 profile 与记住的用户名以便再次显示登录页;本地体验退出清除本地会话和活动 profile,回到提供方选择。
|
||||||
|
|
||||||
App 按构建变体声明远端可用性:debug 的 ABox 入口明确是开发模拟,release 的 ABox 因传输安全待确认而禁用;兼容后端在协议明确前始终禁用;本地体验始终可用。App 没有依赖或创建 `AbsdkBridge`,也没有对 `@CleartextAbsdkTransport` opt-in。
|
两个提供方在所有构建变体中始终可用,不存在按 debug/release 区分的可用性开关。
|
||||||
|
|
||||||
登录完成后进入 `authenticated` 协作路由。当前仅有占位页面,设备列表与主导航由 alZerNest 的设备导航模块接管。
|
登录完成后进入 `authenticated` 协作路由。当前仅有占位页面,设备列表与主导航由 alZerNest 的设备导航模块接管。
|
||||||
|
|
||||||
## 10. 后续边界
|
## 11. 后续边界
|
||||||
|
|
||||||
后续 KremeCN 工作保持为独立短期分支:
|
Room 与设备业务 DataStore 的具体 schema/key 只在对应数据所有权明确后创建。生产 ABox 设备目录由设备目录模块交付后替换 debug 构建中的临时 `FakeDeviceCatalog` 占位。历史示例中的 AsyncTask、明文密码存储、全局明文网络和散落 SDK 调用不得进入正式架构。
|
||||||
|
|
||||||
- 在获批传输控制明确后,单独评审真实 ABox Bridge 的 App 绑定;
|
|
||||||
- `feat/compatible-server`:在协议与连接方式确认后建立服务端、CLI 和 Docker 基础。
|
|
||||||
|
|
||||||
Room 与设备业务 DataStore 的具体 schema/key 只在对应数据所有权明确后创建。历史示例中的 AsyncTask、明文密码存储、全局明文网络和散落 SDK 调用不得进入正式架构。
|
|
||||||
|
|||||||
+50
-58
@@ -13,18 +13,20 @@
|
|||||||
仓库目前主要包含:
|
仓库目前主要包含:
|
||||||
|
|
||||||
- 产品需求概要;
|
- 产品需求概要;
|
||||||
- ABSDK 0630 接口文档;
|
- ABSDK 0630 接口文档与协议观测记录;
|
||||||
- AsyncTask 登录示例;
|
- 正式 Android 应用工程(含提供方登录与本地体验运行时);
|
||||||
|
- ABSDK 防腐层、领域接口、模拟运行时和测试 Fake;
|
||||||
- 清理归档后的 ABSDK Android Sample;
|
- 清理归档后的 ABSDK Android Sample;
|
||||||
- Git 和 AI 工具协作规则。
|
- Git 和 AI 工具协作规则。
|
||||||
|
|
||||||
当前还没有正式的 Android 应用工程、自有后端、自动化测试或 CI Runner。
|
当前还没有设备目录、插座温湿度、红外和情景模式的正式实现,也没有 CI Runner。
|
||||||
|
|
||||||
重要参考资料:
|
重要参考资料:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
docs/requirement_spec.md
|
docs/requirement_spec.md
|
||||||
docs/ABSDK接口部分_0630.md
|
docs/protocol/absdk-0630.md
|
||||||
|
docs/architecture.md
|
||||||
docs/examples/
|
docs/examples/
|
||||||
samples/abox-sdk-sample/
|
samples/abox-sdk-sample/
|
||||||
```
|
```
|
||||||
@@ -49,42 +51,46 @@ ABox Manager 是面向 Android 手机和平板的智能家居管理应用,首
|
|||||||
|
|
||||||
## 4. MVP 范围
|
## 4. MVP 范围
|
||||||
|
|
||||||
### 4.1 登录
|
### 4.1 ABox 登录
|
||||||
|
|
||||||
|
以下登录要求只适用于 ABox 提供方;本地体验不需要凭据,也不显示登录页面。
|
||||||
|
|
||||||
- 支持用户名和密码登录;
|
- 支持用户名和密码登录;
|
||||||
- 支持记住用户名;
|
- 支持记住用户名;
|
||||||
- 支持按连接配置独立开启自动登录;
|
- 支持独立开启自动登录;
|
||||||
- 自动登录所需密码必须通过 Android Keystore 安全保存;
|
- 自动登录所需密码必须通过 Android Keystore 安全保存;
|
||||||
- ABSDK Token 由 SDK 自身管理;进程重启或 Token 失效后,通过保存的凭据重新登录;
|
- ABSDK Token 由 SDK 自身管理;进程重启或 Token 失效后,通过保存的凭据重新登录;
|
||||||
- 退出登录时保留非敏感连接信息和用户名,清除密码与会话;
|
- 退出登录时保留用户名,清除密码与会话。
|
||||||
- 切换后端提供方前必须退出当前会话。
|
|
||||||
|
|
||||||
### 4.2 提供方模式
|
### 4.2 提供方模式
|
||||||
|
|
||||||
应用计划兼容三种相互独立的模式:
|
应用提供两种入口,认证前必须选择其一:
|
||||||
|
|
||||||
1. **ABox 后端**:使用现有 ABSDK 0630 连接 ABox 服务;
|
1. **ABox**:通过 ABSDK 0630 连接当前局域网中的智能家居网关;
|
||||||
2. **自有兼容后端**:连接自行实现的 ABSDK 0630 协议兼容服务;
|
2. **本地体验**:不访问网络或 ABSDK,通过本地模拟数据直接进入完整应用流程。
|
||||||
3. **本地体验**:不连接远端服务,通过本地模拟数据体验完整应用流程。
|
|
||||||
|
首版不提供自有兼容后端入口,也不再规划兼容服务端。
|
||||||
|
|
||||||
约束:
|
约束:
|
||||||
|
|
||||||
- 任一时刻只使用一个提供方;
|
- 任一时刻只启用一个提供方;
|
||||||
- 不要求同时连接两个后端;
|
- 切换提供方前必须退出当前会话;
|
||||||
- ABox 与自有后端的账号、会话和数据不互相绑定;
|
- 每个提供方的会话、设备、遥控器、情景和凭据空间互不混用;
|
||||||
- 每个连接配置拥有独立的设备、遥控器、情景和凭据空间;
|
|
||||||
- 本地体验不启动 HTTP 服务,也不调用 ABSDK。
|
- 本地体验不启动 HTTP 服务,也不调用 ABSDK。
|
||||||
|
|
||||||
### 4.3 设备目录
|
### 4.3 设备目录
|
||||||
|
|
||||||
ABSDK 0630 当前没有已确认的设备列表接口,因此首版设备目录采用:
|
ABSDK 0630 当前没有已确认的设备列表接口,也不提供设备目录。首版设备目录按提供方区分:
|
||||||
|
|
||||||
|
- ABox:由设备目录模块负责的本地持久化目录(二维码批量导入,用户手工添加、编辑和删除);
|
||||||
|
- 本地体验:由模拟运行时内置的模拟设备目录。
|
||||||
|
|
||||||
|
共同约束:
|
||||||
|
|
||||||
- 二维码批量导入;
|
|
||||||
- 用户手工添加、编辑和删除;
|
|
||||||
- 设备名称作为调用 ABSDK 的设备标识;
|
- 设备名称作为调用 ABSDK 的设备标识;
|
||||||
- 设备类型首版只包含插座、温湿度和红外。
|
- 设备类型首版只包含插座、温湿度和红外。
|
||||||
|
|
||||||
不得假设存在尚未确认的新版 SDK 或设备发现接口。
|
不得假设存在尚未确认的新版 SDK 或远程设备发现接口。
|
||||||
|
|
||||||
### 4.4 插座
|
### 4.4 插座
|
||||||
|
|
||||||
@@ -178,25 +184,15 @@ ABSDK 0630 当前没有已确认的设备列表接口,因此首版设备目录
|
|||||||
- 切换提供方前必须结束当前会话;
|
- 切换提供方前必须结束当前会话;
|
||||||
- `docs/examples/` 和 `samples/abox-sdk-sample/` 只作为参考,不直接作为正式架构。
|
- `docs/examples/` 和 `samples/abox-sdk-sample/` 只作为参考,不直接作为正式架构。
|
||||||
|
|
||||||
### 5.3 自有兼容后端
|
### 5.3 模拟运行时
|
||||||
|
|
||||||
自有后端目标是兼容 ABSDK 0630 的必要服务端行为。
|
本地体验由生产模块 `:runtime:simulation` 提供确定性模拟实现:
|
||||||
|
|
||||||
暂定方向:
|
- 不依赖网络、ABSDK 或 Android API;
|
||||||
|
- 内置固定的模拟设备目录和设备状态;
|
||||||
|
- 与 ABox 共用同一套领域端口,UI 不感知差异。
|
||||||
|
|
||||||
- Kotlin 和 Ktor;
|
测试专用的脚本化 Fake 保留在 `:testing:fakes`,不进入生产依赖。
|
||||||
- 旧协议只存在于兼容适配边界;
|
|
||||||
- 内部使用类型化领域模型;
|
|
||||||
- 密码使用强哈希保存;
|
|
||||||
- 酒店与房间作为数据隔离边界;
|
|
||||||
- 管理操作通过内置 CLI 完成;
|
|
||||||
- 提供模拟设备驱动;
|
|
||||||
- 为未来真实设备驱动预留统一接口;
|
|
||||||
- SQLite 用于轻量部署;
|
|
||||||
- PostgreSQL 用于较大规模部署;
|
|
||||||
- Docker 作为标准交付方式。
|
|
||||||
|
|
||||||
具体协议、签名和连接方式必须先验证,不在本文档中提前固化。
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -222,21 +218,20 @@ ABSDK 0630 当前没有已确认的设备列表接口,因此首版设备目录
|
|||||||
- 建立 Compose、Navigation、Hilt、Room 和 DataStore 基础;
|
- 建立 Compose、Navigation、Hilt、Room 和 DataStore 基础;
|
||||||
- 建立公共设计系统基础;
|
- 建立公共设计系统基础;
|
||||||
- 接入和封装 ABSDK 0630;
|
- 接入和封装 ABSDK 0630;
|
||||||
- 建立统一领域接口、错误模型和 Fake 实现;
|
- 建立统一领域接口、错误模型和测试 Fake;
|
||||||
- 实现 ABox、自有兼容后端和本地体验三个入口;
|
- 实现 ABox 和本地体验两个入口,以及按活动提供方的设备操作路由;
|
||||||
- 实现记住用户名、自动登录、Keystore 凭据保存和退出;
|
- 实现记住用户名、自动登录、Keystore 凭据保存和退出;
|
||||||
- 处理 Token 失效与重新登录;
|
- 处理 Token 失效与重新登录;
|
||||||
- 研究 SDK 已确认行为和协议边界;
|
- 研究 SDK 已确认行为和协议边界。
|
||||||
- 建立自有兼容后端基础、测试宿主、CLI 和 Docker 基础。
|
|
||||||
|
|
||||||
主要交付:
|
主要交付:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
工程基础
|
工程基础
|
||||||
SDK 适配层
|
SDK 适配层(AbsdkBridge)
|
||||||
|
本地体验模拟运行时
|
||||||
登录与提供方选择
|
登录与提供方选择
|
||||||
公共领域接口与 Fake
|
公共领域接口与测试 Fake
|
||||||
兼容后端基础
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6.2 alZerNest:设备列表导航
|
### 6.2 alZerNest:设备列表导航
|
||||||
@@ -402,8 +397,7 @@ tzh:
|
|||||||
|
|
||||||
退出条件:
|
退出条件:
|
||||||
|
|
||||||
- Android App 可以使用 Fake 完成主要页面导航;
|
- Android App 可以使用 Fake 或本地体验完成主要页面导航;
|
||||||
- 服务端骨架可以独立启动;
|
|
||||||
- 所有人拥有可独立测试的模块。
|
- 所有人拥有可独立测试的模块。
|
||||||
|
|
||||||
### 阶段 2:完整功能实现
|
### 阶段 2:完整功能实现
|
||||||
@@ -412,8 +406,7 @@ tzh:
|
|||||||
- 完成登录和提供方隔离;
|
- 完成登录和提供方隔离;
|
||||||
- 完成设备目录导入和维护;
|
- 完成设备目录导入和维护;
|
||||||
- 完成插座、温湿度和红外;
|
- 完成插座、温湿度和红外;
|
||||||
- 完成情景模式;
|
- 完成情景模式。
|
||||||
- 完成自有兼容后端的已确认协议范围。
|
|
||||||
|
|
||||||
退出条件:
|
退出条件:
|
||||||
|
|
||||||
@@ -423,8 +416,7 @@ tzh:
|
|||||||
|
|
||||||
### 阶段 3:真实集成
|
### 阶段 3:真实集成
|
||||||
|
|
||||||
- 连接真实 ABox 环境;
|
- 在网关局域网内连接真实 ABox 环境;
|
||||||
- 连接自有兼容后端;
|
|
||||||
- 使用真实插座、温湿度和红外设备;
|
- 使用真实插座、温湿度和红外设备;
|
||||||
- 验证 Token 失效、设备离线和错误码;
|
- 验证 Token 失效、设备离线和错误码;
|
||||||
- 验证手机和平板布局。
|
- 验证手机和平板布局。
|
||||||
@@ -432,7 +424,7 @@ tzh:
|
|||||||
退出条件:
|
退出条件:
|
||||||
|
|
||||||
- 三类真实硬件核心流程通过;
|
- 三类真实硬件核心流程通过;
|
||||||
- ABox 与自有后端连接行为明确;
|
- ABox 局域网连接行为明确;
|
||||||
- 已知限制完整记录。
|
- 已知限制完整记录。
|
||||||
|
|
||||||
### 阶段 4:发布验收
|
### 阶段 4:发布验收
|
||||||
@@ -459,7 +451,6 @@ tzh:
|
|||||||
feat/project-foundation
|
feat/project-foundation
|
||||||
feat/absdk-bridge
|
feat/absdk-bridge
|
||||||
feat/provider-login
|
feat/provider-login
|
||||||
feat/compatible-server
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### alZerNest
|
### alZerNest
|
||||||
@@ -530,17 +521,18 @@ feat/app-integration
|
|||||||
|
|
||||||
- 领域模型和执行逻辑单元测试;
|
- 领域模型和执行逻辑单元测试;
|
||||||
- SDK 返回和错误映射测试;
|
- SDK 返回和错误映射测试;
|
||||||
|
- 提供方选择、会话协调和设备操作路由测试;
|
||||||
|
- 模拟运行时行为测试;
|
||||||
- ViewModel 状态测试;
|
- ViewModel 状态测试;
|
||||||
- Room 持久化测试;
|
- Room 持久化测试;
|
||||||
- Compose 核心页面测试;
|
- Compose 核心页面测试;
|
||||||
- 情景顺序执行和失败继续测试;
|
- 情景顺序执行和失败继续测试。
|
||||||
- 自有兼容后端认证、存储和模拟驱动测试;
|
|
||||||
- Docker 和 CLI 验证。
|
|
||||||
|
|
||||||
### 11.2 手工验收
|
### 11.2 手工验收
|
||||||
|
|
||||||
- 登录、自动登录和退出;
|
- ABox 登录、自动登录和退出;
|
||||||
- 三种提供方入口;
|
- 本地体验直接进入应用;
|
||||||
|
- 两种提供方入口;
|
||||||
- 数据和凭据隔离;
|
- 数据和凭据隔离;
|
||||||
- 设备目录导入和维护;
|
- 设备目录导入和维护;
|
||||||
- 插座状态和控制;
|
- 插座状态和控制;
|
||||||
@@ -573,11 +565,11 @@ Runner 就绪后,再将相同命令配置为受保护 `main` 的必要检查
|
|||||||
- ABSDK 0630 的完整初始化流程;
|
- ABSDK 0630 的完整初始化流程;
|
||||||
- `setHostInfo` 的正式业务含义;
|
- `setHostInfo` 的正式业务含义;
|
||||||
- ABox 官方部署所需参数;
|
- ABox 官方部署所需参数;
|
||||||
- 自有后端与原始 JAR 的最终连接方式;
|
|
||||||
- SDK 的完整签名算法和参数规则;
|
- SDK 的完整签名算法和参数规则;
|
||||||
- SDK 线程安全与会话清理行为;
|
- SDK 线程安全与会话清理行为;
|
||||||
- 真实测试账号、设备名称和硬件环境;
|
- 真实测试账号、设备名称和硬件环境;
|
||||||
- 自有后端连接真实设备所使用的网关协议;
|
- 授权凭据下完整的 ABox 登录与设备操作冒烟验证;
|
||||||
|
- JAR 硬编码域名与局域网网关地址之间的映射机制(详见 `docs/protocol/absdk-0630.md`);
|
||||||
- ABSDK 二进制的生产分发许可。
|
- ABSDK 二进制的生产分发许可。
|
||||||
|
|
||||||
上述事项必须通过厂商资料、授权分析、实验或真实环境验证后,再更新本文档或对应技术文档。
|
上述事项必须通过厂商资料、授权分析、实验或真实环境验证后,再更新本文档或对应技术文档。
|
||||||
|
|||||||
+28
-13
@@ -11,7 +11,7 @@
|
|||||||
- 历史 Sample:`samples/abox-sdk-sample/login-mac/`;
|
- 历史 Sample:`samples/abox-sdk-sample/login-mac/`;
|
||||||
- 公开 API 使用 `javap` 验证,协议细节通过授权字节码分析验证。
|
- 公开 API 使用 `javap` 验证,协议细节通过授权字节码分析验证。
|
||||||
|
|
||||||
本文不是自有兼容后端的最终规范。真实连接参数、部署行为和硬件结果仍须通过授权测试环境验证。
|
本文只记录厂商 JAR 与局域网环境的已确认行为,不定义任何兼容服务端规范。尚未验证的内容见文末清单,不得作为产品实现承诺。
|
||||||
|
|
||||||
## 2. JAR 公开类型
|
## 2. JAR 公开类型
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ commons-logging-1.1.3.jar
|
|||||||
|
|
||||||
JAR 内含宽松的 TLS 信任实现。正式产品不得把这一历史传输行为扩展为 App 其他网络请求的安全策略,也不得记录密码、Token、API Key 或敏感红外载荷。
|
JAR 内含宽松的 TLS 信任实现。正式产品不得把这一历史传输行为扩展为 App 其他网络请求的安全策略,也不得记录密码、Token、API Key 或敏感红外载荷。
|
||||||
|
|
||||||
真实 Bridge 工厂使用 `@CleartextAbsdkTransport` 作为编译期 opt-in 门禁,并且当前没有接入 Android App。该标记只防止误接入,不会为链路提供加密。生产集成前必须确定并批准 HTTPS、受控加密代理或其他能够提供机密性与完整性的传输控制;在此之前不得启用真实 ABox 入口。
|
App 组合根绑定真实 Bridge 时使用 `@CleartextAbsdkTransport` 作为编译期 opt-in 门禁,并声明 `INTERNET` 权限与明文传输许可。该标记只防止误接入,不会为链路提供加密;允许明文是项目所有者对当前局域网集成约束的明确风险接受,不代表传输具备机密性或完整性。
|
||||||
|
|
||||||
## 6. `setHostInfo` 的已确认行为
|
## 6. `setHostInfo` 的已确认行为
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@ roomNo
|
|||||||
apikey
|
apikey
|
||||||
```
|
```
|
||||||
|
|
||||||
其中第一个参数只写入请求字段 `url`,不会修改 SDK 的硬编码 HTTP 基础地址。因此原始 JAR 不能通过该公开 API 直接切换到任意自有后端。
|
其中第一个参数只写入请求字段 `url`,不会修改 SDK 的硬编码 HTTP 基础地址(见第 5 节)。因此该公开 API 不能用于切换请求目标。
|
||||||
|
|
||||||
仍未确认:
|
仍未确认:
|
||||||
|
|
||||||
@@ -136,9 +136,23 @@ apikey
|
|||||||
- hotel、room 和 API Key 的正式取值;
|
- hotel、room 和 API Key 的正式取值;
|
||||||
- 初始化失败对后续登录和设备操作的影响。
|
- 初始化失败对后续登录和设备操作的影响。
|
||||||
|
|
||||||
所以 `feat/absdk-bridge` 不实现或调用 `setHostInfo`。
|
Bridge 不实现或调用 `setHostInfo`。
|
||||||
|
|
||||||
## 7. MVP 端点与数据
|
## 7. 局域网网关观测证据(2026-08-24)
|
||||||
|
|
||||||
|
以下为 2026-08-24 在网关所在局域网内获得的观测结果,仅描述当天环境,不构成通用承诺:
|
||||||
|
|
||||||
|
- 网关地址 `192.168.100.1` 在端口 80 和 443 上可达;
|
||||||
|
- 未携带 Token 直接 `POST http://192.168.100.1/abox/index.php/abjhsdk/user/validate` 返回 `code=00000`、`status=0`;
|
||||||
|
- `feat/moler-infrared-control` 分支的真实硬件测试表明:当前网络环境下,厂商 JAR 能够到达真实网关并完成红外相关操作。
|
||||||
|
|
||||||
|
同时必须保留以下边界:
|
||||||
|
|
||||||
|
- JAR 仍然硬编码基础地址 `a-box.com.cn`;它在该环境中被映射到局域网网关的机制属于外部环境依赖,机制未知,且不受 `setHostInfo` 影响;
|
||||||
|
- 尚未建立 JAR 可用的通用基础地址或主机配置能力,也没有完成携带授权凭据的登录冒烟验证;
|
||||||
|
- 观测结果不能外推为“任意网络下均可连通”,后续环境变化须重新验证。
|
||||||
|
|
||||||
|
## 8. MVP 端点与数据
|
||||||
|
|
||||||
| SDK 方法 | 端点 | 关键参数或返回 |
|
| SDK 方法 | 端点 | 关键参数或返回 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
@@ -154,7 +168,7 @@ apikey
|
|||||||
|
|
||||||
`downloadIrCodes(List<IrInfo>)` 并不是单次批量 HTTP 请求。JAR 按输入顺序逐项调用下载端点,并返回每项 `status`。只要有任一项失败,总体代码为 `20204`,同时 `dicDatas["ret"]` 仍包含逐项结果。
|
`downloadIrCodes(List<IrInfo>)` 并不是单次批量 HTTP 请求。JAR 按输入顺序逐项调用下载端点,并返回每项 `status`。只要有任一项失败,总体代码为 `20204`,同时 `dicDatas["ret"]` 仍包含逐项结果。
|
||||||
|
|
||||||
## 8. 请求签名
|
## 9. 请求签名
|
||||||
|
|
||||||
字节码显示 SDK 会:
|
字节码显示 SDK 会:
|
||||||
|
|
||||||
@@ -165,9 +179,9 @@ apikey
|
|||||||
5. 按时间戳计算的位置插入时间片段并添加固定前缀;
|
5. 按时间戳计算的位置插入时间片段并添加固定前缀;
|
||||||
6. 在请求的 `system` 数据中提交签名、时间戳和 Token。
|
6. 在请求的 `system` 数据中提交签名、时间戳和 Token。
|
||||||
|
|
||||||
这些事实用于判断协议边界,不在本轮重新实现签名算法或对外宣称兼容性。正式兼容后端开始前,必须建立脱敏签名测试向量并复核每个字段和编码细节。
|
这些事实用于判断协议边界,本轮不重新实现签名算法,也不对外宣称兼容性。任何需要复现该协议行为的工作开始前,必须先建立脱敏签名测试向量并复核每个字段和编码细节。
|
||||||
|
|
||||||
## 9. 响应结构
|
## 10. 响应结构
|
||||||
|
|
||||||
字节码解析的响应结构为:
|
字节码解析的响应结构为:
|
||||||
|
|
||||||
@@ -183,7 +197,7 @@ apikey
|
|||||||
|
|
||||||
当前 Bridge 对成功数据进行防御性解析:缺失字段、未知状态或错误类型不会导致 `ClassCastException` 泄漏到调用方。
|
当前 Bridge 对成功数据进行防御性解析:缺失字段、未知状态或错误类型不会导致 `ClassCastException` 泄漏到调用方。
|
||||||
|
|
||||||
## 10. 错误码来源
|
## 11. 错误码来源
|
||||||
|
|
||||||
完整错误码表来自厂商文档和历史 `AboxConstants.java`。Bridge 保留原始 `externalCode`,并映射为以下领域分类:
|
完整错误码表来自厂商文档和历史 `AboxConstants.java`。Bridge 保留原始 `externalCode`,并映射为以下领域分类:
|
||||||
|
|
||||||
@@ -199,7 +213,7 @@ apikey
|
|||||||
|
|
||||||
错误 `msg` 只作为诊断 detail,不直接作为最终 UI 文案。
|
错误 `msg` 只作为诊断 detail,不直接作为最终 UI 文案。
|
||||||
|
|
||||||
## 11. 历史 Sample 观察
|
## 12. 历史 Sample 观察
|
||||||
|
|
||||||
历史 Sample:
|
历史 Sample:
|
||||||
|
|
||||||
@@ -212,14 +226,15 @@ apikey
|
|||||||
|
|
||||||
正式实现只复用已确认的 SDK 调用事实,不复制 AsyncTask、明文凭据或全局明文网络配置。
|
正式实现只复用已确认的 SDK 调用事实,不复制 AsyncTask、明文凭据或全局明文网络配置。
|
||||||
|
|
||||||
## 12. 仍待确认
|
## 13. 仍待确认
|
||||||
|
|
||||||
- ABox 官方初始化的完整流程和参数;
|
- ABox 官方初始化的完整流程和参数;
|
||||||
- 文档所称 Token 两小时有效期在真实环境中的精确表现;
|
- 文档所称 Token 两小时有效期在真实环境中的精确表现;
|
||||||
- Token 失效时各设备接口实际返回的代码;
|
- Token 失效时各设备接口实际返回的代码;
|
||||||
- SDK 的厂商线程安全保证;
|
- SDK 的厂商线程安全保证;
|
||||||
- 真实账号、设备名称和硬件环境;
|
- 授权凭据下完整的 ABox 登录与设备操作冒烟验证;
|
||||||
- 原始 JAR 指向自有兼容后端的最终授权方案;
|
- JAR 硬编码域名与局域网网关地址之间的映射机制(第 7 节);
|
||||||
|
- 网络环境变化(不同网段、DHCP、路由策略)下连通性是否保持;
|
||||||
- ABSDK 和附属 JAR 的生产分发许可;
|
- ABSDK 和附属 JAR 的生产分发许可;
|
||||||
- 所有端点的完整表单编码和可重复签名测试向量。
|
- 所有端点的完整表单编码和可重复签名测试向量。
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
## 需求规格
|
## 需求规格
|
||||||
|
|
||||||
**登录**
|
**连接方式**
|
||||||
1. 记住已登录用户信息功能:记住我
|
1. ABox:通过 ABSDK 连接当前局域网中的智能家居网关,登录成功后进入应用。
|
||||||
2. 自动登录:选中自动登录之后
|
2. 本地体验:不访问网络或 ABSDK,直接建立模拟会话并进入应用。
|
||||||
|
3. 首版不提供自有兼容后端入口。
|
||||||
|
|
||||||
|
**ABox 登录**
|
||||||
|
1. 记住已登录用户信息功能:记住我(仅适用于 ABox)
|
||||||
|
2. 自动登录:选中自动登录之后(仅适用于 ABox)
|
||||||
|
|
||||||
**设备列表**
|
**设备列表**
|
||||||
1. 设备列表:显示设备名称(插座、温湿度、红外)
|
1. 设备列表:显示设备名称(插座、温湿度、红外)
|
||||||
|
|||||||
@@ -152,16 +152,7 @@ No feature UI selects Real or Fake directly.
|
|||||||
|
|
||||||
## Provider Availability
|
## Provider Availability
|
||||||
|
|
||||||
`ProviderAvailability` is simplified to the two supported options. Both are enabled in all build types:
|
As implemented, `ProviderAvailability` was deleted entirely: both remaining options are always enabled, so an availability model with disabled states has no caller. The provider selection screen lists exactly ABox and local experience in every build type, with no per-provider availability state or disabled reason.
|
||||||
|
|
||||||
```kotlin
|
|
||||||
data class ProviderAvailability(
|
|
||||||
val abox: Availability = Availability.Enabled,
|
|
||||||
val local: Availability = Availability.Enabled,
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
`Availability.Simulation` and compatible-backend-specific disabled reasons are removed unless another current UI requirement uses them.
|
|
||||||
|
|
||||||
## Android Transport
|
## Android Transport
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user