## Summary - add a root README with project overview, setup, usage, architecture, security, and contribution guidance - replace stale planning and requirement notes with current 1.0 project overview - update architecture and hardware validation docs to match the implemented app - remove obsolete UI branch notes and the old Java/XML AsyncTask example - remove the superpowers documentation and move vendor ABSDK references into docs/vendor - preserve vendor Markdown and XLS content byte-for-byte ## Verification - Markdown relative links checked - vendor files verified as 100% Git renames - git diff --check passed - no application tests run; documentation-only change Reviewed-on: #15 Co-authored-by: KremeCN <3265494849@qq.com>
242 lines
8.7 KiB
Markdown
242 lines
8.7 KiB
Markdown
# ABSDK 0630 已确认事实与边界
|
||
|
||
## 1. 文档范围
|
||
|
||
本文记录 `libABSDK0630.jar`、厂商接口文档和仓库历史 Sample 中能够复核的事实,并明确仍待真实环境确认的内容。
|
||
|
||
证据来源:
|
||
|
||
- JAR:`samples/abox-sdk-sample/login-mac/libs/libABSDK0630.jar`;
|
||
- 厂商文档:`docs/vendor/ABSDK接口部分_0630.md`;
|
||
- 历史 Sample:`samples/abox-sdk-sample/login-mac/`;
|
||
- 公开 API 使用 `javap` 验证,协议细节通过授权字节码分析验证。
|
||
|
||
本文只记录厂商 JAR 与局域网环境的已确认行为,不定义任何兼容服务端规范。尚未验证的内容见文末清单,不得作为产品实现承诺。
|
||
|
||
## 2. JAR 公开类型
|
||
|
||
### `com.dhc.absdk.ABSDK`
|
||
|
||
JAR 提供 `getInstance()` 单例入口以及以下与 MVP 有关的方法:
|
||
|
||
```text
|
||
ABRet loginWithUsername(String username, String password)
|
||
ABRet isValidateToken()
|
||
ABRet setHostInfo(String url, String hotelName, String roomNo, String apikey)
|
||
ABRet getSockStatus(String soDevName)
|
||
ABRet sockCtrl(String soDevName, String status)
|
||
ABRet getThStatus(String thDevName)
|
||
ABRet sendIr(String irDevName, String irKey)
|
||
ABRet studyIrByIrDevName(String irDevName, String irKey)
|
||
ABRet downloadIrCodes(List<IrInfo> irInfos)
|
||
```
|
||
|
||
JAR 还包含窗帘、开关、射灯、门磁、人体活动和一氧化碳相关接口,但不属于当前 MVP。
|
||
|
||
JAR 没有公开的设备列表、设备发现、logout 或 Token setter API。
|
||
|
||
### `com.dhc.absdk.ABRet`
|
||
|
||
```text
|
||
String getCode()
|
||
String getMsg()
|
||
Map<String, Object> getDicDatas()
|
||
```
|
||
|
||
`"00000"` 表示调用成功;其他字符串代码表示失败。Bridge 不向领域层泄漏 `ABRet`、Map 或厂商类型。
|
||
|
||
### `com.dhc.absdk.IrInfo`
|
||
|
||
```text
|
||
String irDevName
|
||
String key
|
||
String code
|
||
String status
|
||
```
|
||
|
||
下载结果的 `status` 是字符串:`"0"` 表示失败,`"1"` 表示成功。
|
||
|
||
## 3. 文档与 JAR 差异
|
||
|
||
厂商 Markdown 文档把温湿度方法写成:
|
||
|
||
```text
|
||
getThStatusByDevName(String)
|
||
```
|
||
|
||
JAR 实际公开的方法是:
|
||
|
||
```text
|
||
getThStatus(String)
|
||
```
|
||
|
||
Bridge 必须以实际 JAR 方法为准。
|
||
|
||
`setHostInfo` 是 JAR 的公开方法,但未出现在厂商 Markdown 接口清单中。
|
||
|
||
## 4. 全局状态与线程边界
|
||
|
||
JAR 使用单例 `ABSDK`,登录成功后把 Token 保存在 SDK 的静态状态中;后续请求从该全局状态读取 Token。HTTP Client 和 HTTP Context 也由 SDK 共享。
|
||
|
||
由此得到当前 Bridge 约束:
|
||
|
||
- 任一时刻只维护一个活动 ABSDK 会话;
|
||
- 所有 SDK 调用必须在后台执行;
|
||
- 所有 SDK 调用默认串行化;
|
||
- 切换提供方前必须退出 Bridge 本地会话;
|
||
- JAR 没有 logout,Bridge 的 logout 只能清除本地会话并阻止后续调用;
|
||
- Bridge 不通过反射访问或清理 SDK 私有 Token;重新登录会覆盖 SDK 中的 Token。
|
||
|
||
JAR 自身是否保证并发线程安全仍未得到厂商确认。
|
||
|
||
## 5. 传输事实
|
||
|
||
字节码确认 SDK 的基础地址硬编码为:
|
||
|
||
```text
|
||
http://a-box.com.cn/abox/index.php/
|
||
```
|
||
|
||
SDK 使用 Apache HttpClient 4.x,所有已检查业务请求均为 POST。归档 Sample 同时包含:
|
||
|
||
```text
|
||
httpclient-4.3.6.jar
|
||
httpcore-4.3.3.jar
|
||
commons-codec-1.6.jar
|
||
commons-logging-1.1.3.jar
|
||
```
|
||
|
||
JAR 内含宽松的 TLS 信任实现。正式产品不得把这一历史传输行为扩展为 App 其他网络请求的安全策略,也不得记录密码、Token、API Key 或敏感红外载荷。
|
||
|
||
App 组合根绑定真实 Bridge 时使用 `@CleartextAbsdkTransport` 作为编译期 opt-in 门禁,并声明 `INTERNET` 权限与明文传输许可。该标记只防止误接入,不会为链路提供加密;允许明文是项目所有者对当前局域网集成约束的明确风险接受,不代表传输具备机密性或完整性。
|
||
|
||
## 6. `setHostInfo` 的已确认行为
|
||
|
||
`setHostInfo(url, hotelName, roomNo, apikey)` 向以下端点发送初始化请求:
|
||
|
||
```text
|
||
POST abjhsdk/init
|
||
```
|
||
|
||
四个参数作为表单字段提交:
|
||
|
||
```text
|
||
url
|
||
hotelName
|
||
roomNo
|
||
apikey
|
||
```
|
||
|
||
其中第一个参数只写入请求字段 `url`,不会修改 SDK 的硬编码 HTTP 基础地址(见第 5 节)。因此该公开 API 不能用于切换请求目标。
|
||
|
||
仍未确认:
|
||
|
||
- 正式业务中四个字段的具体语义;
|
||
- ABox 官方环境是否要求每次启动调用;
|
||
- hotel、room 和 API Key 的正式取值;
|
||
- 初始化失败对后续登录和设备操作的影响。
|
||
|
||
Bridge 不实现或调用 `setHostInfo`。
|
||
|
||
## 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 方法 | 端点 | 关键参数或返回 |
|
||
|---|---|---|
|
||
| `setHostInfo` | `abjhsdk/init` | `url`、`hotelName`、`roomNo`、`apikey` |
|
||
| `loginWithUsername` | `abjhsdk/user/login` | `username`、SDK 内部 MD5 处理后的 `password`;返回 `token` |
|
||
| `isValidateToken` | `abjhsdk/user/validate` | 返回 `status`:`0`/`1` |
|
||
| `getSockStatus` | `abjhsdk/sock/properties` | `name`;返回 `status`:`0`/`1` |
|
||
| `sockCtrl` | `abjhsdk/zigbee/sock/{device}` | `status`:`0`/`1` |
|
||
| `getThStatus` | `abjhsdk/th/properties` | `name`;返回 `temperature`、`humidity` |
|
||
| `sendIr` | `abjhsdk/ir/{device}/send` | `irKey` |
|
||
| `studyIrByIrDevName` | `abjhsdk/ir/{device}/study` | `irKey` |
|
||
| `downloadIrCodes` | `abjhsdk/ir/{device}/download` | 每项发送 `irKey`、`irCode` |
|
||
|
||
`downloadIrCodes(List<IrInfo>)` 并不是单次批量 HTTP 请求。JAR 按输入顺序逐项调用下载端点,并返回每项 `status`。只要有任一项失败,总体代码为 `20204`,同时 `dicDatas["ret"]` 仍包含逐项结果。
|
||
|
||
## 9. 请求签名
|
||
|
||
字节码显示 SDK 会:
|
||
|
||
1. 取得秒级时间戳;
|
||
2. 对业务参数键排序并组装签名原文;
|
||
3. 加入端点、时间戳和 SDK 内部 secret;
|
||
4. 使用 MD5 生成摘要;
|
||
5. 按时间戳计算的位置插入时间片段并添加固定前缀;
|
||
6. 在请求的 `system` 数据中提交签名、时间戳和 Token。
|
||
|
||
这些事实用于判断协议边界,本轮不重新实现签名算法,也不对外宣称兼容性。任何需要复现该协议行为的工作开始前,必须先建立脱敏签名测试向量并复核每个字段和编码细节。
|
||
|
||
## 10. 响应结构
|
||
|
||
字节码解析的响应结构为:
|
||
|
||
```json
|
||
{
|
||
"code": "00000",
|
||
"msg": "...",
|
||
"data": {}
|
||
}
|
||
```
|
||
|
||
`data` 被转换为 `ABRet.dicDatas`。解析或请求失败时,SDK 可返回 `20000` 和请求失败信息。
|
||
|
||
当前 Bridge 对成功数据进行防御性解析:缺失字段、未知状态或错误类型不会导致 `ClassCastException` 泄漏到调用方。
|
||
|
||
## 11. 错误码来源
|
||
|
||
完整错误码表来自厂商文档和历史 `AboxConstants.java`。Bridge 保留原始 `externalCode`,并映射为以下领域分类:
|
||
|
||
- Token 无效;
|
||
- 认证失败;
|
||
- 网络错误;
|
||
- 请求参数错误;
|
||
- 设备不存在;
|
||
- 设备离线;
|
||
- 无数据;
|
||
- 操作失败;
|
||
- 未知错误。
|
||
|
||
错误 `msg` 只作为诊断 detail,不直接作为最终 UI 文案。
|
||
|
||
## 12. 历史 Sample 观察
|
||
|
||
历史 Sample:
|
||
|
||
- 直接调用 `ABSDK.getInstance()`;
|
||
- 使用 Executor 或 AsyncTask 把同步调用移出 UI 线程;
|
||
- 没有调用 `setHostInfo`;
|
||
- logout 是空实现;
|
||
- 使用普通 SharedPreferences 明文保存密码;
|
||
- 全局允许明文网络。
|
||
|
||
正式实现只复用已确认的 SDK 调用事实,不复制 AsyncTask、明文凭据或全局明文网络配置。
|
||
|
||
## 13. 仍待确认
|
||
|
||
- ABox 官方初始化的完整流程和参数;
|
||
- 文档所称 Token 两小时有效期在真实环境中的精确表现;
|
||
- Token 失效时各设备接口实际返回的代码;
|
||
- SDK 的厂商线程安全保证;
|
||
- 授权凭据下完整的 ABox 登录与设备操作冒烟验证;
|
||
- JAR 硬编码域名与局域网网关地址之间的映射机制(第 7 节);
|
||
- 网络环境变化(不同网段、DHCP、路由策略)下连通性是否保持;
|
||
- ABSDK 和附属 JAR 的生产分发许可;
|
||
- 所有端点的完整表单编码和可重复签名测试向量。
|
||
|
||
这些事项验证前不得作为产品实现承诺。
|