# iOS 自动打包服务 基于 FastAPI + Vue 3 的 iOS 应用自动打包服务,支持 Ad_Hoc 和 App_Store 两种打包类型,提供 Web 界面操作、实时日志流、构建历史管理、多用户权限和健康监测。 ## 目录 - [环境要求](#环境要求) - [快速开始](#快速开始) - [配置说明](#配置说明) - [服务管理](#服务管理) - [多用户管理](#多用户管理) - [Watchdog 健康监测](#watchdog-健康监测) - [macOS 开机自启](#macos-开机自启) - [开发模式](#开发模式) - [自动化测试](#自动化测试) - [项目结构](#项目结构) - [常见问题](#常见问题) --- ## 环境要求 | 依赖 | 版本要求 | 说明 | |------|----------|------| | macOS | 11+ | 必须,xcodebuild 依赖 | | Xcode | 14+ | 必须,含 Command Line Tools | | Python | 3.9+ | 后端运行 | | Node.js | 18+ | 前端构建 | | CocoaPods | - | 项目已有 Podfile 时需要 | ## 快速开始 ### 1. 克隆项目 ```bash git clone BuildServer cd BuildServer ``` ### 2. 配置环境变量 ```bash cp .env.example .env vim .env ``` **建议优先检查的配置项:** ```bash # 分支源码根目录,默认在当前项目下 GIT_SOURCE_BASE=/path/to/iOSBuildServer/ReadoorBranches # 打包输出目录,默认在当前项目下 BUILD_BASE_DIR=/path/to/iOSBuildServer/build # Git 远程仓库地址(配置后可自动拉取分支) GIT_REMOTE_URL=git@github.com:org/repo.git # 管理员密码(建议修改) ADMIN_PASSWORD=your_secure_password ``` ### 3. 构建与启动 ```bash # 一键构建(安装依赖 + 构建前端) ./deploy.sh build # 启动服务 ./deploy.sh start ``` 启动后访问 `http://<服务器IP>:8000` 即可使用。 ### 4.(可选)初始化分支源码目录 系统现在默认直接从分支源码目录打包,每个分支对应 `GIT_SOURCE_BASE` 下的一个子目录。 如果已配置 `GIT_REMOTE_URL`,首次打包某个分支时会自动 clone;如果未配置,则需要先手动准备分支目录: ```bash # 创建分支源码根目录 mkdir -p /path/to/ReadoorBranches # 手动 clone 主分支(后续可继续手动维护) git clone -b main git@github.com:org/repo.git /path/to/ReadoorBranches/main ``` 如果已配置 `GIT_REMOTE_URL`,其他分支无需手动 clone,首次打包时会自动拉取。 ### 5.(可选)启用健康监测 ```bash ./deploy.sh watchdog ``` ### 6.(可选)设为开机自启 ```bash ./deploy/install-service.sh install ``` --- ## 配置说明 所有配置通过项目根目录的 `.env` 文件管理,修改后重启服务生效。 ### 目录配置 | 变量 | 示例 | 说明 | |------|------|------| | `GIT_SOURCE_BASE` | `/Users/shen/Work/Code/iOSBuildServer/ReadoorBranches` | 分支源码根目录,每个分支一个子目录,仅提供 iOS 工程源码 | | `BUILD_BASE_DIR` | `/Users/shen/Work/Code/iOSBuildServer/build` | 打包产物输出基础目录 | | `GIT_REMOTE_URL` | `git@github.com:org/repo.git` | 远程仓库地址,分支目录不存在时自动 clone | ### 服务配置 | 变量 | 默认值 | 说明 | |------|--------|------| | `BACKEND_PORT` | `8000` | 后端服务端口 | | `ADMIN_USERNAME` | `admin` | 初始管理员用户名(首次启动自动创建) | | `ADMIN_PASSWORD` | `admin123` | 初始管理员密码 | | `JWT_SECRET` | `ios-build-server-secret-key-change-in-production` | JWT 签名密钥(生产环境务必修改) | ### 打包配置 | 变量 | 默认值 | 说明 | |------|--------|------| | `MAX_CONCURRENT_BUILDS` | `2` | 最大并行打包数 | | `BUILD_DIR_RETENTION_HOURS` | `24` | 打包目录保留时间(小时),超期自动清理 | | `BUILD_TIMEOUT_HOURS` | `1` | 打包超时时间(小时),超时自动标记失败 | ### Web 管理配置 以下配置通过管理后台 Web 界面管理(存储在 `config.json`): 首次部署时,如果项目根目录下存在 `config.json`,系统会自动导入其中的 `apps` 和 `schemes` 作为初始配置;导入后即可继续在后台增删改。 | 配置项 | 说明 | |--------|------| | App 管理 | 应用名称、Scheme、服务器环境、upload_key 等 | | Scheme 管理 | 打包 Scheme 配置 | | 服务器环境 | 测试/正式/自定义环境的 API 地址、Universal Link 等 | | 分支管理 | 可打包的代码分支列表 | | 版本号 | 服务端统一管理 App_Ver 和 Build_Ver,不修改分支源码 | | 上传配置 | 服务端内置 OSS / WebDAV 分发,生成 IPA、manifest、下载页和二维码 | ### 服务端自动化资源 项目内的 `backend/automation/` 是 Web 打包服务唯一使用的自动化资源:默认皮肤和混淆工具都在此处维护。分支源码中的 `AutoPacking/` 不会被复制、执行或修改,仍可供开发者手动打包使用。 ### Watchdog 配置 | 变量 | 默认值 | 说明 | |------|--------|------| | `WATCHDOG_INTERVAL` | `30` | 健康检查间隔(秒) | | `WATCHDOG_TIMEOUT` | `10` | HTTP 健康检查超时(秒) | | `MAX_RESTART_ATTEMPTS` | `3` | 连续重启上限,超过后进入冷却 | | `COOLDOWN_SECONDS` | `300` | 冷却时间(秒) | --- ## 服务管理 所有服务管理通过 `deploy.sh` 完成: ```bash ./deploy.sh ``` ### 命令一览 | 命令 | 说明 | |------|------| | `build` | 构建前端、创建 Python 虚拟环境、安装所有依赖 | | `start` | 后台启动服务 | | `stop` | 停止服务和 watchdog | | `restart` | 重启服务 | | `status` | 查看服务和 watchdog 运行状态 | | `test` | 一键运行全部测试(后端 + 前端) | | `watchdog` | 启动健康监测(后台守护) | | `watchdog-stop` | 停止健康监测 | | `watchdog-fg` | 前台运行健康监测(调试用) | ### 常用操作 ```bash # 首次部署 ./deploy.sh build && ./deploy.sh start # 查看状态 ./deploy.sh status # 更新代码后重新部署 git pull ./deploy.sh build ./deploy.sh restart # 启用健康监测 ./deploy.sh watchdog # 停止所有服务 ./deploy.sh stop ``` ### 日志 日志文件位于 `logs/` 目录: ``` logs/ ├── server.log # 服务运行日志 ├── watchdog.log # Watchdog 操作日志(重启记录等) ├── server-stdout.log # launchd 模式下的标准输出 ├── server-stderr.log # launchd 模式下的标准错误 ├── watchdog-stdout.log # launchd watchdog 标准输出 └── watchdog-stderr.log # launchd watchdog 标准错误 ``` --- ## 多用户管理 系统支持多用户管理,基于 JWT 认证。首次启动时自动创建 `.env` 中配置的管理员账号。 ### 用户角色 | 角色 | 权限 | |------|------| | 管理员 | 所有功能 + 用户管理(增删改查、角色切换) | | 普通用户 | 打包、查看历史、查看配置(不可修改配置、不可管理用户) | ### 管理用户 在管理后台「用户管理」页面(仅管理员可见): - 创建用户:设置用户名、密码(至少 6 位)、是否管理员 - 修改密码:管理员可修改任意用户密码 - 切换角色:在管理员/普通用户之间切换 - 删除用户:不能删除自己 ### 认证流程 1. `POST /api/auth/login` — 用户名+密码登录,返回 JWT token 2. 后续请求在 `Authorization: Bearer ` 头中携带 token 3. Token 有效期 24 小时,过期需重新登录 --- ## Watchdog 健康监测 Watchdog 定期检查服务健康状态,发现异常自动重启。 ### 检测逻辑 ``` 每 N 秒执行一次 │ ├─ 进程是否存在? (kill -0) │ └─ 否 → 重启 │ └─ HTTP /api/health 返回 200? ├─ 是 → 正常,继续轮询 └─ 否 → 重启 ``` ### 重启保护 - 连续失败次数 <= `MAX_RESTART_ATTEMPTS`:立即重启 - 连续失败次数 > `MAX_RESTART_ATTEMPTS`:进入冷却期(`COOLDOWN_SECONDS` 秒),冷却结束后重置计数器重新尝试 ### 运行方式 ```bash # 后台守护(推荐) ./deploy.sh watchdog # 前台运行(调试,可看到实时输出) ./deploy.sh watchdog-fg # 查看 watchdog 日志 tail -f logs/watchdog.log # 停止 watchdog ./deploy.sh watchdog-stop ``` --- ## macOS 开机自启 通过 macOS 原生的 launchd 实现开机自启和进程守护。 ### 安装 ```bash # 前置条件:先完成构建 ./deploy.sh build # 安装服务 ./deploy/install-service.sh install ``` 安装后会注册两个 launchd 服务: | 服务 | 说明 | |------|------| | `com.readoor.buildserver` | 主服务,进程崩溃自动拉起 | | `com.readoor.buildserver.watchdog` | 健康监测,检测 HTTP 卡死并重启 | ### 卸载 ```bash ./deploy/install-service.sh uninstall ``` ### 手动管理 launchd 服务 ```bash # 查看服务状态 launchctl list | grep readoor # 手动停止 launchctl unload ~/Library/LaunchAgents/com.readoor.buildserver.plist launchctl unload ~/Library/LaunchAgents/com.readoor.buildserver.watchdog.plist # 手动启动 launchctl load ~/Library/LaunchAgents/com.readoor.buildserver.plist launchctl load ~/Library/LaunchAgents/com.readoor.buildserver.watchdog.plist ``` --- ## 开发模式 一键启动本地开发环境(后端 + 前端同时运行): ```bash ./start.sh ``` - 前端界面:`http://localhost:3000`(自动代理 API 请求到后端) - 后端 API:`http://localhost:8000` - 前端修改自动热更新,后端修改自动 reload - `Ctrl+C` 同时停止所有服务 --- ## 自动化测试 ### 运行测试 ```bash # 一键运行全部测试(后端 89 + 前端 35 = 124 个) ./deploy.sh test # 只运行匹配的测试 ./deploy.sh test -k test_login # 单独运行后端测试 .venv/bin/python -m pytest tests/ -v # 单独运行前端测试 cd frontend && npx vitest run ``` ### 测试覆盖 | 测试文件 | 覆盖内容 | 数量 | |----------|----------|------| | `test_api_health.py` | 健康检查 | 1 | | `test_api_auth.py` | 登录认证 | 3 | | `test_api_config.py` | App/Scheme/Branch/Server/Build 配置 CRUD | 20 | | `test_api_tasks.py` | 任务创建/列表/详情/取消 | 9 | | `test_api_apps.py` | 打包选择接口 | 3 | | `test_websocket.py` | 日志流订阅/发送/完成/清理 | 10 | | `test_downloads.py` | dSYM/混淆映射/二维码下载 | 11 | | `test_build_service.py` | 源码更新/拷贝/配置生成/目录清理 | 11 | | `test_build_queue.py` | 并发控制/任务执行/取消 | 7 | | `test_edge_cases.py` | 边界情况/无效参数/配置备份 | 14 | | `App.test.js` | 登录/退出/导航 | 8 | | `BuildView.test.js` | 打包表单/任务列表/提交 | 8 | | `ConfigView.test.js` | 配置管理/分支增删/设置保存 | 8 | | `HistoryView.test.js` | 历史列表/过滤/下载/二维码 | 11 | --- ## 项目结构 ``` BuildServer/ ├── .env.example # 环境变量模板 ├── .env # 实际配置(不入库) ├── .gitignore ├── README.md # 项目文档 ├── deploy.sh # 部署与管理脚本 ├── start.sh # 开发模式启动脚本(一键启动前后端) ├── requirements.txt # Python 依赖 ├── requirements-dev.txt # 测试依赖(pytest, httpx) ├── pytest.ini # pytest 配置 │ ├── deploy/ # 部署相关 │ └── install-service.sh # macOS launchd 服务安装 │ ├── tests/ # 后端测试(pytest) │ ├── conftest.py # 测试 fixtures │ ├── test_api_*.py # API 接口测试 │ ├── test_websocket.py # WebSocket 测试 │ ├── test_downloads.py # 文件下载测试 │ ├── test_build_service.py # 打包服务测试 │ ├── test_build_queue.py # 队列测试 │ └── test_edge_cases.py # 边界情况测试 │ ├── backend/ # 后端(FastAPI) │ ├── main.py # 入口,路由注册,静态文件服务 │ ├── config.py # 配置加载(读取 .env) │ ├── database.py # SQLAlchemy 数据库初始化 │ ├── models.py # 数据库模型(Task, BuildConfig, User) │ ├── schemas.py # Pydantic 请求/响应模型 │ ├── deps.py # JWT 认证依赖 │ ├── routers/ │ │ ├── auth.py # 登录认证(JWT) │ │ ├── users.py # 用户管理(仅管理员) │ │ ├── config.py # 配置管理(App/Scheme/Server/Upload/Branch/Version CRUD) │ │ ├── apps.py # 打包选择(只读) │ │ └── tasks.py # 任务管理(创建/列表/取消/下载) │ └── services/ │ ├── build_service.py # 打包核心流程 │ ├── build_queue.py # 异步任务队列 │ └── log_streamer.py # WebSocket 日志流 │ └── frontend/ # 前端(Vue 3 + Vite) ├── vite.config.js # 构建配置,开发代理 ├── vitest.config.js # 前端测试配置 ├── index.html └── src/ ├── App.vue # 根组件(导航/登录) ├── router/index.js # 路由 ├── composables/ │ └── useWebSocket.js ├── views/ │ ├── BuildView.vue # 打包页面 │ ├── HistoryView.vue # 历史记录 │ └── ConfigView.vue # 管理后台 └── __tests__/ # 前端测试(vitest) ├── App.test.js ├── BuildView.test.js ├── ConfigView.test.js └── HistoryView.test.js ``` --- ## 常见问题 ### Q: 打包时提示 "未找到 xcodebuild" 确保安装了 Xcode 和 Command Line Tools: ```bash xcode-select --install xcodebuild -version ``` ### Q: 前端页面打不开 检查前端是否已构建: ```bash ls backend/static/index.html # 应该存在 # 如果不存在: ./deploy.sh build ./deploy.sh restart ``` ### Q: 端口被占用 修改 `.env` 中的 `BACKEND_PORT`,然后重启: ```bash vim .env ./deploy.sh restart ``` ### Q: 打包目录占满磁盘 调整保留时间或手动清理: ```bash # 缩短保留时间 vim .env # BUILD_DIR_RETENTION_HOURS=12 ./deploy.sh restart # 手动清理所有打包目录 rm -rf /path/to/build/output/build_readoor_* ``` ### Q: Watchdog 频繁重启 查看 watchdog 日志定位原因: ```bash tail -50 logs/watchdog.log tail -50 logs/server.log ``` 常见原因: - `GIT_SOURCE_BASE` 下对应分支目录不存在,且未配置 `GIT_REMOTE_URL` - 磁盘空间不足 - Python 依赖缺失(重新执行 `./deploy.sh build`) ### Q: 如何修改管理员密码 **方法一**:通过管理后台「用户管理」页面修改(推荐) **方法二**:编辑 `.env` 后重启(仅影响初始管理员账号): ```bash ADMIN_PASSWORD=new_password ./deploy.sh restart ``` 注意:`.env` 中的管理员账号仅在首次启动时创建,之后的密码修改请通过管理后台操作。 ### Q: 多台 Mac 部署 每台 Mac 上: ```bash git clone cd BuildServer cp .env.example .env # 编辑 .env 配置路径和密码 ./deploy.sh build ./deploy.sh start ./deploy.sh watchdog ``` 各机器独立运行,配置互不影响。 ### Q: 如何按分支打包 1. 在 `.env` 中配置 `GIT_SOURCE_BASE` 和 `GIT_REMOTE_URL` 2. 在管理页面「分支管理」中添加需要打包的分支(默认已有 `main`) 3. 打包时在「代码分支」下拉框中选择分支 4. 首次打包某个分支时会自动从远程 clone,后续打包会自动 `git pull` 更新 5. 每个分支有独立的源码目录,支持并行打包不同分支 ### Q: 分支目录占满磁盘怎么办 ```bash # 查看各分支目录大小 du -sh /path/to/ReadoorBranches/* # 删除不用的分支目录 rm -rf /path/to/ReadoorBranches/old-branch ``` ### Q: 如何运行测试 ```bash # 一键运行全部测试(后端 + 前端) ./deploy.sh test # 只运行后端测试 .venv/bin/python -m pytest tests/ -v # 只运行前端测试 cd frontend && npx vitest run # 运行指定测试 ./deploy.sh test -k test_login ```