From ec3ffb9db338eccb9f1ef276f557ed71cc8ed163 Mon Sep 17 00:00:00 2001 From: chick Date: Mon, 14 Sep 2026 18:22:23 +0800 Subject: [PATCH] =?UTF-8?q?docs(ios):=20=E5=90=8C=E6=AD=A5=200.2.x=20?= =?UTF-8?q?=E5=AE=9E=E5=86=B5=E6=96=87=E6=A1=A3=E4=B8=8E=E8=A7=84=E5=88=92?= =?UTF-8?q?=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 + README.md | 22 +- apps/ios/Assets/AppIcon.svg | 26 --- apps/ios/README.md | 53 +++++ docs/ios-native-0.2.0.md | 2 +- docs/ios-native-0.2.1.md | 14 +- docs/ios-native.md | 188 ++++++++++++++++++ .../2026-09-08-ios-native-ipa-foundation.md | 72 ++++--- .../specs/2026-09-08-ios-native-ipa-design.md | 19 ++ 9 files changed, 339 insertions(+), 60 deletions(-) delete mode 100644 apps/ios/Assets/AppIcon.svg create mode 100644 apps/ios/README.md create mode 100644 docs/ios-native.md diff --git a/.gitignore b/.gitignore index 54e667c..2d6d48e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,6 @@ apps/web/dist/ apps/ios/.build/ build/ data/ + +# 误在工作副本里跑构建时留下的缓存目录 +apps/ios/apps/ diff --git a/README.md b/README.md index 7086ff9..74c5764 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,27 @@ ## iOS Native 应用 -`apps/ios` 提供不依赖 8788 控制台的原生 iPhone 应用。当前 0.2.1 保留节点总览、标签筛选与分组、跨实例短信、实例详情、日志诊断、全局外观切换和本地数据管理;构建方式见 [docs/ios-native-0.2.1.md](docs/ios-native-0.2.1.md)。 +`apps/ios` 提供不依赖 8788 控制台的原生 iPhone 应用,当前版本 **0.2.1 (build 6)**,运行在 iOS 16 及以上,产物为未签名 IPA,供 TrollStore 或自有签名流程安装。iOS 开发在 `ios-native-ipa` 分支进行。 + +底部为节点、消息、设置三个入口: + +- **节点**:运行概览、分组视图、标签多选筛选、搜索、批量选择、实例增删改,卡片直连实例详情。 +- **实例详情**:设备、SIM、蜂窝网络、系统资源、CPU、连接状态六个模块,敏感值默认脱敏,显示后离开页面即隐藏。 +- **消息**:跨实例短信读取、按实例与方向筛选、搜索、发送、删除。 +- **设置**:主题外观(跟随系统 / 浅色 / 深色)、应用信息、本地数据与日志中心、隐私与数据、数据清理。 + +实例信息与密码保存在应用沙盒本地文件,会话 Cookie 只存在于进程内存,不使用 Keychain,不上传任何数据。应用只访问用户添加的节点地址,上游路径为固定白名单。 + +按产品决策移除的能力:全局访问密码、定时与后台调度、iOS 远程推送、自动备份与自动清理、控制台自更新,以及依赖常驻进程的应用内通知中心(日志中心因此收进设置,不再单独占一个底部入口)。 + +构建与自检: + +```bash +./scripts/build-ios-ipa.sh # 产出 build/ipa/MultiSimAdmin.ipa 与 .sha256 +cd apps/ios && swift test # 48 个用例 +``` + +文档:现行说明 [docs/ios-native.md](docs/ios-native.md),发布记录 [0.2.1](docs/ios-native-0.2.1.md) 与 [0.2.0](docs/ios-native-0.2.0.md)。 ## 功能 diff --git a/apps/ios/Assets/AppIcon.svg b/apps/ios/Assets/AppIcon.svg deleted file mode 100644 index 0ff9523..0000000 --- a/apps/ios/Assets/AppIcon.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/ios/README.md b/apps/ios/README.md new file mode 100644 index 0000000..30b39ec --- /dev/null +++ b/apps/ios/README.md @@ -0,0 +1,53 @@ +# MultiSimAdmin iOS + +iPhone 原生应用的 Swift Package。产品与技术说明见 [docs/ios-native.md](../../docs/ios-native.md), +本文件只写这个目录里怎么动手。 + +## 目录 + +```text +Sources/MultiSimAdmin/ + AppMetadata.swift 版本号与 Bundle ID 的唯一来源 + MultiSimAdminApp.swift 入口、三个底部 Tab、调试直达参数 + Models/ 实例、分组、查询等值类型 + Features/{Fleet,Device,Messages,Logs,Settings}/ 页面与 view model + Upstream/ 路由白名单、HTTP 客户端、按实例隔离的会话 Cookie + Services/ 连接探测、凭据存储、依赖装配 + Persistence/ 沙盒 JSON 文件仓储与日志存储 + Theme/ 颜色令牌、按钮与卡片样式、骨架、主题模式 + Support/ 错误文案、时间显示、调试启动 + Resources/ Info.plist、Assets.xcassets +Tests/MultiSimAdminTests/ 48 个用例 +Design/ 图标生成脚本与参考稿 +``` + +## 常用命令 + +```bash +swift build +swift test +xcodebuild -scheme MultiSimAdmin \ + -destination 'platform=iOS Simulator,id=' \ + -configuration Debug build +swift Design/generate_app_icon.swift \ + Sources/MultiSimAdmin/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon1024.png +``` + +未签名 IPA 从仓库根目录执行 `./scripts/build-ios-ipa.sh` 生成。 + +## 发版要改的地方 + +版本号必须四处一致,否则测试会失败: + +1. `Sources/MultiSimAdmin/Resources/Info.plist` 的 `CFBundleShortVersionString` 与 `CFBundleVersion` +2. `Sources/MultiSimAdmin/AppMetadata.swift` +3. `Tests/MultiSimAdminTests/AppMetadataTests.swift` +4. `Tests/MultiSimAdminTests/SettingsViewModelTests.swift` + +改完补一份 `docs/ios-native-.md` 发布说明,并同步更新 `docs/ios-native.md`、仓库根 +README 的版本引用。 + +## 界面约定 + +主操作只用一种蓝色,危险操作只用红色;同屏并排控件等高;选中态不得改变控件尺寸;标签统一 +28pt 胶囊;卡片内部不再嵌套卡片;不得出现因配色而在深色背景上消失的按钮或文字。 diff --git a/docs/ios-native-0.2.0.md b/docs/ios-native-0.2.0.md index 9b77f40..c57f5b7 100644 --- a/docs/ios-native-0.2.0.md +++ b/docs/ios-native-0.2.0.md @@ -1,6 +1,6 @@ # iOS Native 0.2.0 -MultiSimAdmin 0.2.0 是面向 iPhone 的原生 IPA 版本。应用直接连接用户添加的 SimAdmin 节点,不需要先启动 8788 控制台。 +MultiSimAdmin 0.2.0 是面向 iPhone 的原生 IPA 版本。应用直接连接用户添加的 SimAdmin 节点,不需要先启动 8788 控制台。本文是历史发布说明,现行说明见 [docs/ios-native.md](ios-native.md)。 ## 本次变更 diff --git a/docs/ios-native-0.2.1.md b/docs/ios-native-0.2.1.md index 3a869d1..d47ec8a 100644 --- a/docs/ios-native-0.2.1.md +++ b/docs/ios-native-0.2.1.md @@ -1,6 +1,6 @@ # iOS Native 0.2.1 -0.2.1 (6) 在 0.2.0 的基础上做界面与图标重构,功能集合不变。 +0.2.1 (6) 在 0.2.0 的基础上做界面与图标重构,功能集合不变。应用的整体结构、页面能力、上游白名单和本地数据布局见现行说明 [docs/ios-native.md](ios-native.md),本文只记录本次发布的变化。 ## 本次变更 @@ -9,11 +9,21 @@ - 深色主题下标签可见性提高,色雾与描边权重上调,避免浅底可读、深底消失。 - 消息卡片去掉分隔线并压缩内边距,单屏可见消息数由 2.5 条提升到 3.5 条。 - 节点详情的分区卡片收紧行距,"设备"分区同一屏位由 3 行增加到 5 行。 -- 节点详情头部指标由 8 行精简为 4 行(号码、运营商、网络、IP),数据模块由 6 枚胶囊改为一条读数,仅在缺模块时展开。 +- 节点详情头部指标收敛为 4 枚仪表(信号、延迟、CPU、内存)与一行身份摘要(号码、运营商、网络、IP),设备型号、固件、存储、运行时间下沉到分区列表;数据模块由 6 枚胶囊改为一条可用度读数,只在真有模块读不到时展开并点名。 - 批量选择勾选框移出实例名称区域,选中与未选中都不再压住文字。 - 批量选择工具栏统一为 34pt 图标按钮,全选、删除、退出三个控件等高。 - 分组编辑器改为点选即生效,去掉常驻禁用的"移出分组"按钮和说明文字。 +## 文档同步 + +本次发布同时补齐了与实现脱节的说明文档: + +- 新增 [docs/ios-native.md](ios-native.md),作为 iOS 应用的现行说明:导航、页面能力、上游接口白名单、本地数据与安全、构建与验证、已确认的移除边界。 +- [docs/superpowers/specs/2026-09-08-ios-native-ipa-design.md](superpowers/specs/2026-09-08-ios-native-ipa-design.md) 加上实现修订段,逐条标出被推翻的决策(五 Tab、通知中心、Keychain、GRDB/SQLite、操作与审计、设备模块范围、配色)。 +- [docs/superpowers/plans/2026-09-08-ios-native-ipa-foundation.md](superpowers/plans/2026-09-08-ios-native-ipa-foundation.md) 标记为已执行完毕,并记录持久化与凭据存储两处偏离。 +- README 的 iOS 章节改写为当前版本、三个入口、移除能力与构建自检命令。 +- 删除未被引用的旧图标参考稿 `apps/ios/Assets/AppIcon.svg`,图标参考只保留 `apps/ios/Design/AppIcon.svg`。 + ## 数据与安全 与 0.2.0 一致:实例信息保存在应用沙盒本地数据文件,实例密码保存在同一沙盒的私有凭据文件,不使用 iOS Keychain,登录会话只存在于进程内存。应用仅连接用户添加的节点地址。 diff --git a/docs/ios-native.md b/docs/ios-native.md new file mode 100644 index 0000000..b8c30c5 --- /dev/null +++ b/docs/ios-native.md @@ -0,0 +1,188 @@ +# iOS 原生应用说明(当前实现) + +本文是 iPhone 应用的唯一现行说明,内容与仓库代码一致。历史设计稿和执行计划保留在 +`docs/superpowers/` 下,其中已被实现推翻的决策在本文第 9 节逐条列出。 + +- 当前版本:`0.2.1 (build 6)` +- 承载分支:`ios-native-ipa` +- 运行要求:iOS 16.0 及以上,`arm64`,Bundle ID `fun.chick.multi-simadmin` +- 产物:未签名 `MultiSimAdmin.ipa`,由 TrollStore 或用户自有签名流程安装 + +## 1. 形态 + +独立 iPhone 应用。应用直接以 HTTP/HTTPS 访问用户添加的每个 SimAdmin 节点,不经过 +8788 控制台,不含 WebView,不内嵌 Node.js,也不与 Web 端共享数据库或进程。Web 前端和 +Node 控制面仍然独立存在,两者只共享上游接口契约。 + +## 2. 导航 + +底部固定三个入口,高度 62pt(`AITabBar`): + +| 入口 | 页面 | 内容 | +| --- | --- | --- | +| 节点 | `FleetView` | 节点总览、运行概览、标签筛选、分组视图、批量选择、添加与编辑实例 | +| 消息 | `MessagesView` | 跨实例短信读取、按实例与方向筛选、搜索、发送、删除 | +| 设置 | `SettingsView` | 主题外观、应用信息、本地数据(进入日志中心)、隐私与数据、数据清理 | + +实例详情 `InstanceDetailView` 由节点卡片进入;日志中心 `LogsView` 只出现在 +「设置 → 本地数据」里,不占用底部入口。启动参数 `--tab-messages`、`--tab-settings` +可直达对应 Tab,`--tab-detail`、`--tab-logs` 只在 Debug 构建生效,供逐页截图验证使用。 + +## 3. 页面能力 + +### 节点总览 + +- 运行概览:在线率、异常节点、检测进度、今日消息、分组与标签统计,可折叠。 +- 分组视图:按分组折叠成段,段头给出该组健康度与台数,支持展开与折叠。 +- 标签筛选:标签条支持多选叠加,标签上直接显示命中台数,可单个取消或全部清除。 +- 搜索:匹配名称、地址、运营商与标签。 +- 节点卡片:号码、运营商、制式、温度、电量、内存、存储、延迟、信号、固件、运行时间等 + 指标,超出一屏时折叠为「另有 N 项指标」。 +- 批量选择:工具栏为 34pt 图标按钮(全选、删除、退出等高),勾选列独立于名称区域, + 选中态不遮挡文字。 +- 实例增删改:地址、名称、标签、分组、访问凭据;删除前确认,并一并清除本地登录信息。 + +### 实例详情 + +- 头部卡片:地址、连接状态、四项仪表(信号、延迟、CPU、内存)、身份摘要(号码、运营商、 + 网络、IP)、模块可用度读数、分组与标签。 +- 数据模块:设备、SIM、蜂窝网络、系统资源、CPU、连接状态共 6 个分区,逐模块独立加载, + 单模块失败只标记该模块,不影响其余分区。 +- 敏感值(IMEI、ICCID 等)默认隐藏,需要显式开启显示,离开页面后自动恢复隐藏。 +- 本机保存的配置:地址、凭据状态、标签、分组,以及登录、登出、重新检测。 + +### 消息中心 + +逐实例读取 `/api/sms/list` 后在本地合并,不做跨设备中转: + +- 列表按时间排序,显示来源实例、方向、号码、正文与相对时间。 +- 支持按实例筛选、按上行/下行筛选、按号码或内容搜索。 +- 发送写入目标实例;失败可重试;单条删除走该实例的上游接口。 + +### 日志中心与设置 + +- 日志中心:运行日志统一时间线、连接探测记录(结果、错误码、耗时)、设备诊断快照; + 支持按级别、来源、实例、结果筛选与关键字搜索,支持清理过期连接日志。 +- 设置:主题外观(跟随系统、浅色、深色,即时作用于全部页面)、应用信息与系统版本、 + 本地数据统计、隐私与数据说明、清除运行日志(不可恢复确认)。 + +## 4. 上游访问 + +只允许固定白名单,不存在任意 URL 代理: + +| 方法 | 路径 | 用途 | +| --- | --- | --- | +| GET | `/api/health` | 可达性与版本 | +| GET | `/api/device` | 设备信息 | +| GET | `/api/sim` | SIM 与号码 | +| GET | `/api/network` | 蜂窝网络与信号 | +| GET | `/api/network/signal-strength` | 信号强度明细 | +| GET | `/api/stats` | 系统资源 | +| GET | `/api/stats/cpu` | CPU 明细 | +| GET | `/api/connectivity` | 连接状态 | +| GET | `/api/sms/list` | 短信列表(limit、offset、direction) | +| POST | `/api/sms/send` | 发送短信 | +| POST | `/api/sms/batch-delete` | 批量删除短信 | +| POST | `/api/auth/login` | 使用实例密码换取会话 | +| POST | `/api/auth/logout` | 注销会话 | + +请求超时 30 秒,单响应体上限 262144 字节,错误统一映射为请求非法、需要登录、权限受限、不支持、 +超时、传输失败、响应非法七类可读文案。会话 Cookie 按实例隔离保存在内存中,并绑定创建时 +的节点地址,地址改变后旧 Cookie 立即失效。应用不请求定位、相机、麦克风、通讯录或后台 +刷新权限,不声明任何后台模式。 + +## 5. 本地数据与安全 + +全部数据落在应用沙盒 `Documents` 目录,无 Keychain、无 SQLite、无服务端上传: + +| 文件 | 内容 | +| --- | --- | +| `instances.json` | 实例名称、地址、标签、分组、修订号 | +| `instance-groups.json` | 分组定义 | +| `credentials.json` | 实例访问密码 | +| `log-center.json` | 运行日志、连接探测记录、诊断快照缓存 | + +主题偏好存在 `UserDefaults`(键 `aiThemeMode`)。登录会话只存在于进程内存,应用退出即消失。 +密码与 Cookie 不写日志、不进导出内容。删除应用即彻底清除本机数据。允许 HTTP 明文访问是 +为了兼容局域网 SimAdmin,公网节点应由用户自行通过 HTTPS 反代暴露。 + +## 6. 设计语言 + +深墨蓝与金色构成品牌色,界面在浅色下使用中性冷灰画布与纯白卡片,深色下使用低明度蓝黑分层, +主操作使用蓝色,危险操作使用红色。控件令牌集中在 `AITheme`:主按钮高 48pt(紧凑 44pt、大号 +56pt)、工具栏按钮高 44pt(宽 104pt)、导航栏图标按钮 34pt 方形(圆角 11pt)、输入框高 52pt、 +卡片圆角 22pt、按钮圆角 16pt、标签为 28pt 胶囊。 +同屏并排控件必须等高,选中态不得改变控件尺寸,卡片内部不再嵌套卡片,正文与标题不使用负字距。 + +## 7. 构建与产物 + +```bash +./scripts/build-ios-ipa.sh +``` + +流程:`xcodebuild -scheme MultiSimAdmin -configuration Release`(`generic/platform=iOS`)编译 +可执行文件 → 手工组装 `Payload/MultiSimAdmin.app` → 用 `xcrun actool` 编译 `Assets.xcassets` +得到 `Assets.car` 并合并图标元数据到 `Info.plist` → `zip` 打包 → 生成 `.sha256`。产物: + +- `build/ipa/MultiSimAdmin.ipa` +- `build/ipa/MultiSimAdmin.ipa.sha256` + +脚本不需要证书与描述文件,不做任何签名改动;`Assets.car` 缺失时直接失败退出,避免发布没有 +图标的包。 + +应用图标由脚本光栅化生成,不使用手工位图: + +```bash +cd apps/ios && swift Design/generate_app_icon.swift \ + Sources/MultiSimAdmin/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon1024.png +``` + +图标几何与 Web 端 favicon 一致:深墨蓝底、金色 SIM 面板(切角在左上)、三根底部对齐的递增 +信号条。`apps/ios/Design/AppIcon.svg` 是同构图参考稿,实际构建使用 PNG。 + +## 8. 验证方式 + +```bash +cd apps/ios +swift build +swift test # 48 个用例 +xcodebuild -scheme MultiSimAdmin \ + -destination 'platform=iOS Simulator,id=' \ + -configuration Debug build +``` + +单元测试覆盖实例仓储与修订冲突、地址规范化与去重、标签归一化、上游路由白名单、会话隔离、 +连接探测分类、短信解析与分页、设备快照解析、日志仓储与清理、主题模式持久化、时间相对显示、 +版本号契约。界面改动在 iPhone 17 Pro 模拟器上以截图逐页核对浅色与深色两套主题,重点检查控件 +等高、文字不溢出、按钮在深色下不消失。 + +## 9. 与设计稿的偏离 + +`docs/superpowers/specs/2026-09-08-ios-native-ipa-design.md` 的以下决策已被实现推翻,该文档 +只作为历史背景保留: + +| 原设计 | 当前实现 | 原因 | +| --- | --- | --- | +| 底部五 Tab:节点/消息/通知/日志/设置 | 三 Tab:节点/消息/设置 | 应用内通知中心依赖进程常驻,关闭后不可用;日志属于低频排查,收进设置 | +| 通知通道、规则、投递队列、立即投递 | 未实现 | 同上,移除后不再保留只读残壳 | +| 实例密码存 iOS Keychain | 沙盒内 `credentials.json` | Keychain 在 TrollStore 环境下读写不稳定 | +| GRDB + SQLite 控制面库 | 沙盒内 JSON 文件 | 去掉第三方依赖,数据结构与备份语义更直观 | +| 操作目录、任务、审计、维护、备份 | 未实现 | 高风险写操作与常驻调度不在 iPhone 前台场景内 | +| 设备模块 13 项(含通话、eSIM、OTA、WiFi Calling、自动化) | 6 个只读模块 + 短信读写 | 上游只保留有稳定读取价值的接口,其余按需在后续版本评估 | +| 浅灰画布、青绿主按钮 | 深浅双主题、蓝色主操作、金色品牌色 | 0.2.x 视觉重构结论 | + +## 10. 已确认的移除边界 + +不实现:应用启动后的周期轮询、后台任务与静默推送、Cron 与自动投递、自动备份与自动日志修剪、 +控制台自更新、多用户与远程访问、全局访问密码。 + +保留:进入前台与下拉刷新触发的一次同步、页面可见时的按需刷新、用户主动发起的登录、检测、 +发送、删除与日志清理。 + +## 11. 文档索引 + +- [docs/ios-native.md](ios-native.md):本文,现行说明 +- [docs/ios-native-0.2.1.md](ios-native-0.2.1.md):0.2.1 (6) 发布说明与校验值 +- [docs/ios-native-0.2.0.md](ios-native-0.2.0.md):0.2.0 发布说明 +- [docs/superpowers/specs/2026-09-08-ios-native-ipa-design.md](superpowers/specs/2026-09-08-ios-native-ipa-design.md):历史设计稿 +- [docs/superpowers/plans/2026-09-08-ios-native-ipa-foundation.md](superpowers/plans/2026-09-08-ios-native-ipa-foundation.md):地基执行计划(已完成) diff --git a/docs/superpowers/plans/2026-09-08-ios-native-ipa-foundation.md b/docs/superpowers/plans/2026-09-08-ios-native-ipa-foundation.md index 9d0936b..379b971 100644 --- a/docs/superpowers/plans/2026-09-08-ios-native-ipa-foundation.md +++ b/docs/superpowers/plans/2026-09-08-ios-native-ipa-foundation.md @@ -1,5 +1,18 @@ # iOS Native IPA Foundation Implementation Plan +> **状态:Task 1 - Task 6 已全部完成(2026-09-14,0.2.1 build 6)。** +> +> 执行时有两处偏离本计划的规定,现行事实以 [docs/ios-native.md](../../ios-native.md) 为准: +> +> - **持久化不用 GRDB/SQLite**。计划里的 `instances`、`instance_tags`、`device_groups`、 +> `connection_logs` 等表改为四个沙盒 JSON 文件:`instances.json`、`instance-groups.json`、 +> `credentials.json`、`log-center.json`,仓储与修订冲突语义保持不变。 +> - **实例密码不进 Keychain**。TrollStore 环境下 Keychain 读写不稳定,改用应用沙盒内的 +> `credentials.json`,配合只存在于进程内存的会话 Cookie。 +> +> 计划末尾提到的后续五份计划(消息、通知、操作与审计、日志与维护、设备模块、备份兼容)不再单独 +> 编写:消息与日志已随 0.2.x 落地,通知、操作审计、维护与备份按产品决策移除或暂缓。 + > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Build the native iOS foundation that can compile into an unsigned `MultiSimAdmin.ipa`, persist instances locally, connect safely to SimAdmin upstreams, and render the first fleet workbench. @@ -39,7 +52,7 @@ This is the first of six executable plans. Later plans cover messages, notificat - Produces: SwiftUI entry `MultiSimAdminApp`. - Produces: `scripts/build-ios-ipa.sh`, used by every later UI task. -- [ ] **Step 1: Write the metadata test** +- [x] **Step 1: Write the metadata test** Create `apps/ios/Tests/MultiSimAdminTests/AppMetadataTests.swift`: @@ -58,7 +71,7 @@ final class AppMetadataTests: XCTestCase { } ``` -- [ ] **Step 2: Run the test and verify it fails** +- [x] **Step 2: Run the test and verify it fails** Run from repo root: @@ -68,7 +81,7 @@ cd apps/ios && swift test --filter AppMetadataTests Expected: failure because `MultiSimAdmin` and `AppMetadata` do not yet exist. -- [ ] **Step 3: Create the package and minimal app** +- [x] **Step 3: Create the package and minimal app** Create `apps/ios/Package.swift`: @@ -166,7 +179,7 @@ Create `apps/ios/Sources/MultiSimAdmin/Resources/Info.plist`: ``` -- [ ] **Step 4: Run the test and verify it passes** +- [x] **Step 4: Run the test and verify it passes** ```bash cd apps/ios && swift test --filter AppMetadataTests @@ -174,7 +187,7 @@ cd apps/ios && swift test --filter AppMetadataTests Expected: PASS. -- [ ] **Step 5: Create the IPA builder** +- [x] **Step 5: Create the IPA builder** Create `scripts/build-ios-ipa.sh`: @@ -217,7 +230,7 @@ git add apps/ios scripts/build-ios-ipa.sh git commit -m "feat(ios): add native app foundation" ``` -- [ ] **Step 6: Verify clean IPA build** +- [x] **Step 6: Verify clean IPA build** ```bash scripts/build-ios-ipa.sh @@ -242,7 +255,7 @@ Expected: ARM64 Mach-O executable, valid ZIP, and printed SHA-256. - Produces: `AITheme` with named colors and control dimensions. - Produces: `AIButtonStyle(kind:size:)`, `AICard`, `AITag`, and `AIBrandBar`. -- [ ] **Step 1: Write the token test** +- [x] **Step 1: Write the token test** ```swift import SwiftUI @@ -270,7 +283,7 @@ final class AIThemeTests: XCTestCase { } ``` -- [ ] **Step 2: Run the test and verify it fails** +- [x] **Step 2: Run the test and verify it fails** ```bash cd apps/ios && swift test --filter AIThemeTests @@ -278,7 +291,7 @@ cd apps/ios && swift test --filter AIThemeTests Expected: FAIL because `AITheme` is undefined. -- [ ] **Step 3: Implement theme, buttons, cards, and brand bar** +- [x] **Step 3: Implement theme, buttons, cards, and brand bar** Create `apps/ios/Sources/MultiSimAdmin/Theme/AITheme.swift`: @@ -410,7 +423,7 @@ struct MultiSimAdminApp: App { } ``` -- [ ] **Step 4: Run tests and IPA build** +- [x] **Step 4: Run tests and IPA build** ```bash cd apps/ios && swift test @@ -419,7 +432,7 @@ cd ../.. && scripts/build-ios-ipa.sh Expected: all tests PASS and the IPA is regenerated. -- [ ] **Step 5: Commit** +- [x] **Step 5: Commit** ```bash git add apps/ios @@ -440,7 +453,7 @@ git commit -m "feat(ios): add shared design system" - Consumes: GRDB `DatabaseQueue`. - Produces: `Instance`, `InstanceInput`, `InstancePatch`, `InstanceQuery`, `InstanceRepository`. -- [ ] **Step 1: Write repository tests** +- [x] **Step 1: Write repository tests** Create `apps/ios/Tests/MultiSimAdminTests/InstanceRepositoryTests.swift`: @@ -513,7 +526,7 @@ final class InstanceRepositoryTests: XCTestCase { } ``` -- [ ] **Step 2: Run tests and verify failure** +- [x] **Step 2: Run tests and verify failure** ```bash cd apps/ios && swift test --filter InstanceRepositoryTests @@ -521,7 +534,7 @@ cd apps/ios && swift test --filter InstanceRepositoryTests Expected: FAIL because the persistence types are undefined. -- [ ] **Step 3: Define models and migration** +- [x] **Step 3: Define models and migration** Create `apps/ios/Sources/MultiSimAdmin/Models/InstanceModels.swift`: @@ -857,7 +870,7 @@ private struct InstanceRow: Codable, FetchableRecord, MutablePersistableRecord { } ``` -- [ ] **Step 4: Run repository tests** +- [x] **Step 4: Run repository tests** ```bash cd apps/ios && swift test --filter InstanceRepositoryTests @@ -865,7 +878,7 @@ cd apps/ios && swift test --filter InstanceRepositoryTests Expected: PASS. If GRDB column mapping fails, fix only the mapping code, not the public interface. -- [ ] **Step 5: Commit** +- [x] **Step 5: Commit** ```bash git add apps/ios @@ -885,7 +898,7 @@ git commit -m "feat(ios): add instance persistence" - Produces: `UpstreamRoute`, `UpstreamResponse`, `UpstreamError`, `SimAdminClient`. - Produces: `func send(_ route: UpstreamRoute, baseURL: URL, cookie: String?) async throws -> UpstreamResponse`. -- [ ] **Step 1: Write route and client tests** +- [x] **Step 1: Write route and client tests** ```swift import XCTest @@ -916,7 +929,7 @@ final class UpstreamClientTests: XCTestCase { } ``` -- [ ] **Step 2: Run the tests and verify failure** +- [x] **Step 2: Run the tests and verify failure** ```bash cd apps/ios && swift test --filter UpstreamClientTests @@ -924,7 +937,7 @@ cd apps/ios && swift test --filter UpstreamClientTests Expected: FAIL because upstream types are undefined. -- [ ] **Step 3: Implement routes and client** +- [x] **Step 3: Implement routes and client** Create `apps/ios/Sources/MultiSimAdmin/Upstream/UpstreamRoute.swift`: @@ -1062,7 +1075,7 @@ public struct SimAdminClient: Sendable { } ``` -- [ ] **Step 4: Run tests and commit** +- [x] **Step 4: Run tests and commit** ```bash cd apps/ios && swift test @@ -1086,7 +1099,7 @@ Expected: all tests PASS. - Consumes: `SimAdminClient`, `InstanceRepository`. - Produces: `actor InstanceSessionStore`; protocol `CredentialStore`; `ConnectionProbe.test(_ instance:)`. -- [ ] **Step 1: Write connection probe test** +- [x] **Step 1: Write connection probe test** ```swift import Foundation @@ -1126,7 +1139,7 @@ final class ConnectionProbeTests: XCTestCase { } ``` -- [ ] **Step 2: Run the test and verify failure** +- [x] **Step 2: Run the test and verify failure** ```bash cd apps/ios && swift test --filter ConnectionProbeTests @@ -1134,7 +1147,7 @@ cd apps/ios && swift test --filter ConnectionProbeTests Expected: FAIL because the probe and client protocol are undefined. -- [ ] **Step 3: Implement session, credentials, probe, and client protocol** +- [x] **Step 3: Implement session, credentials, probe, and client protocol** Create `apps/ios/Sources/MultiSimAdmin/Upstream/InstanceSessionStore.swift`: @@ -1271,7 +1284,7 @@ public struct ConnectionProbe: Sendable { } ``` -- [ ] **Step 4: Run tests and commit** +- [x] **Step 4: Run tests and commit** ```bash cd apps/ios && swift test @@ -1296,7 +1309,7 @@ Expected: all tests PASS. - Consumes: `InstanceRepository`, `ConnectionProbe`, `CredentialStore`. - Produces: `@MainActor final class FleetViewModel` with `refresh()`, `add(_:)`, `update(_:)`, and `delete(_ ids: [UUID])`. -- [ ] **Step 1: Write fleet view model test** +- [x] **Step 1: Write fleet view model test** ```swift import XCTest @@ -1325,7 +1338,7 @@ final class FleetViewModelTests: XCTestCase { } ``` -- [ ] **Step 2: Run the test and verify failure** +- [x] **Step 2: Run the test and verify failure** ```bash cd apps/ios && swift test --filter FleetViewModelTests @@ -1333,7 +1346,7 @@ cd apps/ios && swift test --filter FleetViewModelTests Expected: FAIL because the fleet model and test doubles are undefined. -- [ ] **Step 3: Implement view model and SwiftUI screens** +- [x] **Step 3: Implement view model and SwiftUI screens** Create `apps/ios/Sources/MultiSimAdmin/Features/Fleet/FleetViewModel.swift`: @@ -1425,7 +1438,7 @@ Create `apps/ios/Sources/MultiSimAdmin/Features/Fleet/FleetView.swift` with a `N Create `apps/ios/Sources/MultiSimAdmin/Features/Fleet/InstanceFormView.swift` with validated fields for name, origin, tags, group, and optional password. The Save button uses `AIButtonStyle(kind: .primary)` and calls `model.add(_:)`. -- [ ] **Step 4: Add in-memory test doubles** +- [x] **Step 4: Add in-memory test doubles** Append to `apps/ios/Tests/MultiSimAdminTests/FleetViewModelTests.swift`: @@ -1466,7 +1479,7 @@ struct MemoryInstanceRepository: InstanceRepository { Then adapt the test to `let repository = MemoryInstanceRepository()`. -- [ ] **Step 5: Run tests, build IPA, and commit** +- [x] **Step 5: Run tests, build IPA, and commit** ```bash cd apps/ios && swift test @@ -1487,4 +1500,3 @@ Expected: all tests PASS and the IPA contains the fleet UI. 4. **Logs and maintenance plan**: runtime/connection logs, diagnostics, retention, cleanup, optimize, manual backups. 5. **Device modules plan**: overview, cellular, SIM, calls, eSIM, WiFi Calling, device network, OTA, configuration, and per-instance panels. 6. **Organization and compatibility plan**: groups, tags, identities, discovery, database import, component backup compatibility, and release audit. - diff --git a/docs/superpowers/specs/2026-09-08-ios-native-ipa-design.md b/docs/superpowers/specs/2026-09-08-ios-native-ipa-design.md index 0b273c5..a1fb948 100644 --- a/docs/superpowers/specs/2026-09-08-ios-native-ipa-design.md +++ b/docs/superpowers/specs/2026-09-08-ios-native-ipa-design.md @@ -2,6 +2,25 @@ 日期:2026-09-08 +> **实现修订(2026-09-14,0.2.1 build 6)** +> +> 本文是改写启动时的设计稿,保留作为历史背景。以下决策在实现过程中被推翻,现行事实以 +> [docs/ios-native.md](../../ios-native.md) 为准,正文中的旧描述不再单独改写: +> +> - 底部导航为**节点、消息、设置**三个入口,不是本文的五个 Tab。 +> - **应用内通知中心整体移除**:通知依赖常驻进程转发,应用关闭后无法工作,因此通道、规则、 +> 投递队列、手动投递均不实现。 +> - **日志中心不是独立 Tab**,收纳在「设置 → 本地数据」内。 +> - **不使用 iOS Keychain**:TrollStore 环境下 Keychain 读写不稳定,实例密码改存应用沙盒 +> `Documents/credentials.json`,仅内存持有会话 Cookie。 +> - **不使用 GRDB/SQLite**:本地数据改为四个 JSON 文件(`instances.json`、 +> `instance-groups.json`、`credentials.json`、`log-center.json`),不引入第三方依赖。 +> - **操作目录、任务、审计、维护、备份、恢复未实现**:iPhone 前台场景不承载高风险写操作与 +> 调度型能力,本文对应章节按未落地处理。 +> - 设备模块落地为 6 个只读分区(设备、SIM、蜂窝网络、系统资源、CPU、连接状态)加短信读写, +> 本文列出的通话、eSIM、OTA、WiFi Calling、自动化历史未纳入当前版本。 +> - 配色从「浅灰画布 + 青绿主按钮」改为深墨蓝与金色的品牌对,浅色用中性冷灰画布,主操作为蓝色。 + ## 目标 把 multi-simadmin 的管理能力改写为独立 iPhone 应用,而不是为现有 Web 服务做一个远程客户端或 WebView 壳。应用面向 iOS 16+ 和 TrollStore 安装环境,构建流程产出未签名 IPA;Apple 证书、开发者账号、TestFlight 和上架签名不在本项目范围内。