# 开发手册(DEVELOPMENT) 面向本项目开发者:开发流程、git 工作流、环境说明、技术红线、本地开发、常见开发任务。 --- ## 1. 开发流程与 git 工作流 ### 1.1 分支策略 | 分支 | 用途 | |------|------| | `dev` | **开发分支**,所有新功能/修复都在这里开发 | | `main` | **生产分支**(主分支),只放已确认的稳定版本 | 生产环境 = 部署机 `192.168.20.220` 的 `/mnt/data/openstf/auto_control`(python-app 容器运行 `web_server.py`)。 ### 1.2 git 操作铁律(重要) **所有 git 操作都必须先经项目负责人明确确认后才能执行**,包括但不限于: - `commit` / `push`(**即使 push 到 dev 也要确认**) - `merge`(dev → main) - `revert` / `checkout` / `reset` / `branch -D` 等 **标准流程:** ``` 1. 在 dev 分支开发、本地测试 2. 完成改动 → 把改动清单 + 建议 commit 信息 列给负责人 3. 负责人确认 → 才能 commit + push dev 4. 需要发布 → 负责人确认后再合并到 main 5. 部署生产 → 负责人明确指示后才 pull 到 220 ``` > 不允许"开发完顺手就 commit/push"。即使是一次性小改动,也要先确认。 --- ## 2. 环境说明 | 环境 | 位置 | 说明 | |------|------|------| | 开发机 | 本机(192.168.20.57) | `.venv` + 本地运行 `web_server.py` | | 生产机 | 部署机 220 的 `auto_control` | python-app 容器,`network_mode: host` | | STF 服务 | ~~`192.168.20.220:7100`~~ | 已停用(代码已摘除依赖)。注意:此处"已停用"与 [STF_REMOVAL.md](STF_REMOVAL.md) 的"待人工确认"项矛盾(220 侧是否已 `docker stop stf` 未核实),需以 220 实际为准 | | adb 容器 | 220 上 `adb`(host 网络 5037) | USB 设备远程 adb server;网络设备补连用 | | 设备 | Tailscale `100.100.10.x:5555` | Xiaomi 舰队,本机 `100.100.10.2` 在 tailnet 内 | | uiautodev | 本机 `20242` | 元素抓取服务(web_server 自动拉起) | ### 2.1 adb key(关键) - 本机 `~/.android/adbkey` 沿用历史 key(原取自 STF adb 容器,全部设备都信任) - **不要随意更换 key**——设备会变 unauthorized 连不上 - 旧 key 备份在 `~/.android/adbkey.local.bak` - 生产环境的容器也需要用这把 key(部署时处理) ### 2.2 设备连接方式 - 设备 serial 是 `IP:5555`(Tailscale 地址),**直连**优先(只 connect、绝不 disconnect) - USB 设备(serial 无冒号):插本机走本地 adb;插 220 走远程 adb server(`USB_ADB_HOST:5037`) - 本机已在 tailnet 内,直连可靠且快(<1s) - 设备加入/退出平台:工具 → 设备池管理(SQLite 清单,自动连接 + 型号采集) ### 2.3 配置键速查(`config.py` / `.env`) `.env` 加载方式:项目根目录逐行解析、`os.environ.setdefault`(环境变量已设则不覆盖)。以下默认值以 `config.py` 为准: | 键 | 默认值 | 说明 | |------|------|------| | `WEB_HOST` / `WEB_PORT` | `0.0.0.0` / `18050` | Web 后台监听(18050 避开 Windows 动态端口范围) | | `DATA_DIR` / `APK_DIR` | `data/` / `data/apks/` | 持久化数据目录 / APK 存储目录 | | `BACKUP_DIR` / `RESTORE_STAGING_DIR` / `RESTORE_PENDING_DIR` | `data/backups` / `data/restore_staging` / `data/restore_pending` | 系统备份:导出 zip、导入暂存、待重启生效的恢复目录 | | `ADB_PATH` | `bin/adb/adb`(Windows 为 `adb.exe`) | 按平台自动识别,代码只拼路径 | | `USB_ADB_HOST` / `USB_ADB_PORT` | `100.100.10.1` / `5037` | 220 的 adb 容器(host 网络),驱动远程 USB 设备 | | `DISCOVERY_PORT` / `DISCOVERY_SUBNETS` / `DISCOVERY_INTERVAL` | `5555` / 局域网+Tailscale 网段 / `60` | 设备自动发现;可在工具页设备池面板改,存 `app_meta` `discovery_*` 覆盖默认 | | `TAILSCALE_API_KEY` / `TAILSCALE_TAILNET` | 空 / 空 | 工具页 Tailscale 管理(官方 API v2) | | `WEB_SECRET_KEY` | 未配置则随机生成 | 会话密钥(web_server 读 `.env`;不配则重启登录态失效) | | `STF_URL` / `STF_TOKEN` / `STF_SSH_*` | 废弃 | STF 摘除后仅历史保留,代码不再使用 | --- ## 3. 技术红线(开发限制)—— 违反会打断共享 adb transport,需人工恢复 这些是踩过坑后总结的,**任何修改都不能引入**。违反任何一条都会导致设备连接被全部重建(历史原因:STF provider 共享同一 adb transport,摘除 STF 后仍保留此约束): 1. **绝不 `adb kill-server`** - 会断开所有设备的 adb transport,全部设备连接被重建,运行中任务中断 - 见 `core/adb_helper.py` 2. **绝不对 `IP:5555` 设备 `adb disconnect`** - 该地址的 adb transport 是共享的(历史与 STF provider 共用),disconnect 会断掉全部相关连接 - 直连模式下 `release()` 不 disconnect - 见 `core/device_worker.py` `STFDevice.release()` 3. **空闲设备扫描不主动 connect/disconnect** - IP:5555 的 transport 由多方共享(历史与 STF provider 共用),外部 connect/disconnect 会扰动共享连接 - `_ForegroundScanner._scan_free` 对空闲设备直接返回"空闲",不碰 adb - 见 `core/task_manager.py` 4. **adb key 保持历史 key 不变**(见 2.1,设备信任该 key) 5. **直连优先,不引入第三方桥接**(见 2.2) ### 3.1 其他开发限制 - **`web_server.py` 以 `debug=False` 运行,不热重载**:改 `core/`、`tasks/`、`templates/`、`static/` 后必须重启 web_server(前端 HTML 改完强刷浏览器) - **任务参数放各自 `tasks//task.py` 顶部,不放 `config.py`** - **生产环境(220)默认只读**:任何写操作(改文件/重启容器/部署)都必须先经负责人确认 - **数据库是 SQLite**(`data/users.db`,WAL 模式):运行时数据不提交 git - **前端 JS 已拆分多文件**(均位于 `static/admin/`):`monitor.html` 按 `base.js → markdown.js → list.js → monitor.js → editor.js → tasks.js → tools.js → apps.js → admin.js → agent.js → system.js` 的顺序用 `