# iOS 客户端

星线 iOS 是使用 SwiftUI 编写的原生 iPhone 客户端。本文说明工程入口、状态管理、本机数据与系统能力接入，面向需要运行、维护或扩展客户端的开发者。

## 工程与系统要求

`ios-app/project.yml` 是 XcodeGen 工程配置来源，生成的工程名和主 scheme 都是 `StarlineWorkbench`。配置声明 Swift 6.0、最低 iOS 17.0、设备族为 iPhone，Bundle ID 为 `cn.thestarline.workbench`。当前没有 iPad 专用或 watchOS target；独立手表版仍属待办。

项目直接导入 `FoundationModels`，开发环境需要包含该框架的 SDK；仓库 README 的开发流程使用 Xcode 27 和 XcodeGen。最低运行系统与编译 SDK 是不同要求：iOS 17 可以运行基础功能，系统模型识别仅在 iOS 26 及以上且模型可用时启用。

主要外部依赖为 LiveKit Swift SDK（`from: 2.17.0`）和本仓库 `chat-crypto/dist/StarlineChatCrypto.xcframework`。Swift Package 版本声明允许兼容版本解析，不能将下限当作每次构建的实际锁定版本。加密核心需按仓库构建流程准备，详见[消息与媒体](https://document.thestarline.cn/app/messaging-and-media.md)。

## 启动与状态架构

`StarlineWorkbenchApp` 在启动时创建 `ChatStore`，并将其交给 `CallSystemBridge`。根视图分别持有 `LocalWorkspaceStore`、`MemoryStore`、`MomentsStore` 和附近地点状态，通过 SwiftUI Observation、`@State` 与环境传递给功能视图。

默认底部为“聊天、工作台、我的”；记忆可以通过设置加入底部导航。默认页面和扫码按钮开关使用 `@AppStorage` 保存。工作台路由使用 `NavigationStack`，任务编辑、扫码和账号确认使用独立展示状态。界面 locale 当前固定为简体中文。

启动异步恢复待处理登录与聊天会话，回到前台重新检查会话。`onOpenURL` 先尝试身份回调，再处理好友链接，避免把登录回调当作普通扫码内容。身份流程与回调限制见[认证](https://document.thestarline.cn/app/authentication.md)。

## 数据与网络流

任务、网站收藏和最近访问由 `LocalWorkspaceStore` 写入 App 私有的 `workspace.json`。记忆由单独的 `MemoryStore` 管理，其索引、附件和密钥策略见[本地记忆](https://document.thestarline.cn/app/local-memory.md)。这两类本机数据不因聊天登录而自动同步。

聊天通过 `ChatAPI`、`URLSession` 和模型解码访问聊天服务；默认地址为 `https://chat.thestarline.cn`。Debug 可用 `STARLINE_CHAT_BASE_URL` 指定测试地址，代码只接受 HTTPS 或 HTTP 回环主机，并拒绝包含用户信息、查询或片段的覆盖值；Release 不读取该环境覆盖。不要把测试地址或真实凭据写进源码。

新事状态由 `MomentsStore` 复用聊天身份管理；音视频使用 LiveKit，系统来电使用 CallKit/PushKit。扫码使用 VisionKit 的二维码识别，相册图片识别和手动输入保留为替代入口。普通网页与账号确认网页分别管理浏览会话。

## 运行与扩展

在仓库的 `ios-app` 目录执行：

```sh
xcodegen generate
open StarlineWorkbench.xcodeproj
```

选择 `StarlineWorkbench` scheme 运行；新增源文件或修改系统能力后同步 `project.yml` 与工程。新增领域数据应先明确属于本机工作台、加密记忆还是服务端聊天，随后在对应 Store 增加操作，再由视图呈现错误和加载状态，避免直接在视图中混合网络和持久化。

真机签名须使用维护者自己的开发团队与描述文件。工程声明相机、麦克风、使用期间定位，以及 location/audio/voip 后台模式；APNs 环境按 Debug/Release 区分。配置存在不能证明推送、后台定位或通话已完成真机验收，详见[权限与可访问性](https://document.thestarline.cn/app/permissions-accessibility.md)。

## 模块边界与排错入口

| 现象或需求 | 优先检查 | 不能据此推断 |
| --- | --- | --- |
| 本机任务或网站读取失败 | `LocalWorkspaceStore` 的快照解码与原子写入 | 聊天账号重新登录会恢复工作台 |
| 记忆库无法读取 | `MemoryStore.loadError`、Keychain 可用性和文件认证 | 空列表就是原来没有记忆，或改账号密码能恢复密钥 |
| 浏览器成功但账号为空 | `ChatNativeAuth` 的 pending、回调和 exchange | 打开 Account 页面已经取得聊天 token |
| 消息一直 sending／failed | `ChatStore` pending 与 clientId 合并 | 普通队列具备持久离线发件箱 |
| 通话 active 但无画面 | `ChatCallCoordinator` 的 Room、权限与远端轨道 | 信令 active 等于媒体接通 |
| 后台位置未更新 | `ChatLiveLocationManager`、权限、共享范围与更新时间 | 城市贴纸识别会自动开启持续共享 |

会话和 pending 使用聊天 Keychain service，属性为首次解锁后仅本设备可用；记忆密钥使用另一 service，要求当前设备解锁。`LocalWorkspaceStore` 的普通快照不因此共享记忆加密。普通聊天队列属于当前 Store 内存；独立 MLS 传输器才有自己的加密 checkpoint，当前主界面不能继承它的全部恢复能力。

新增功能时需区分主线程状态与异步响应。当前多个关键路径会在 await 后检查 token、用户、聊天目标或 operation，防止迟到结果污染新状态；这不表示所有新增请求可以省掉检查。把页面隐藏、后台暂停、网络重试、进程重建和明确退出各自测试，生命周期细节见[客户端生命周期](https://document.thestarline.cn/app/client-lifecycle.md)。

个人任务的截止筛选和网站去重见[工作台](https://document.thestarline.cn/app/workbench.md)，Date 编码和 vault 格式见[本机数据格式](https://document.thestarline.cn/app/local-data-formats.md)，记忆打包与 Account 对接缺口见[记忆转出](https://document.thestarline.cn/app/memory-export.md)。客户端当前只保存转出契约；权威 Account 版本缺少对应 redeem 路由，不能由分享代码存在推断多因素转出已可用。

## 验证边界

仓库包含领域、存储、加密、聊天、城市贴纸及 UI 测试。本篇依据当前源码编写，本轮未重新构建或启动模拟器，也未核验商店发行版本。历史测试与本次执行结果应分别记录；公网登录、两台真机跨网络通话、后台来电及实际权限恢复仍须走真实路径，参考[测试](https://document.thestarline.cn/app/testing.md)与[发布](https://document.thestarline.cn/app/releases.md)。
