Skip to content

feat(ios): SwiftUI native RoleWeave client (#338) - #341

Merged
PeterGuy326 merged 3 commits into
mainfrom
feat/338-ios-native
Sep 19, 2026
Merged

PeterGuy326 merged 3 commits into
mainfrom
feat/338-ios-native

Conversation

@waterbro-8

Copy link
Copy Markdown
Collaborator

Closes #338

Native SwiftUI app in mobile/ios. Pair with a running RoleWeave host and send commands. Does not share UI with Android or HarmonyOS.

Open mobile/ios/RoleWeave.xcodeproj in Xcode 15+ on a Mac. This CI environment cannot compile iOS.

@xiaocui-big

Copy link
Copy Markdown

平台组 Review(崔泽生,assigned by @冯浩然)

总体印象

9 文件 +545 行,结构清晰,符合 #338 AC:独立 UI、iOS 17、phone-link v1 配对、组织只读预览、指令电脑端执行。SwiftUI 用法地道,@MainActor 正确,视图结构清晰。作为 iOS MVP 骨架合格。

但有几个需要关注的问题。

🔴 关键问题(建议合并前修复)

1. 缺少 Authorization Bearer Token — 违反 API 契约

api-contract-v0.md §1 明确规定 Authorization: Bearer <boot-token>,仅 /health 免 token。但 PhoneSession.swift 的 loadOrg() 和 pair() 都没有设置 Authorization 头——对真实主机发请求会 401。

建议:在 PhoneSession 加 @Published var bootToken 字段,或在配对成功后由服务端下发。

2. 无 WebSocket 重连机制

connectSocket() 建立连接后,listen() 遇到 .failure 只设状态为"连接断开",无重连。Android 端有完整指数退避重连(最多 5 次)。iOS 用户遇到网络抖动只能手动重新配对。建议至少移植 Android 的线性退避逻辑。

3. 合并冲突未解决

mergeable: false,CHANGELOG.md 冲突,需 rebase。

🟡 重要问题

4. sendCommand 不校验 positionId

始终取 roles.first?.id,用户无法选择岗位。如果 snapshot 为 nil,positionId 传 nil。Android 端有显式校验。建议增加角色选择或至少校验非空。

5. 配对码无输入校验

.numberPad 键盘不阻止粘贴非数字或任意长度。建议限制 6 位数字或发送前校验。

6. 无单元测试

Android 附带 PhoneLinkCodecTest.kt(4 用例)。iOS 没有任何测试。建议至少为 handleMessage 解析和 URL 构造建测试。

7. host 默认值无持久化

每次启动重置为 127.0.0.1:8800。建议用 @AppStorage 保存。

🟢 次要

  • WebSocket 无 ping/pong 心跳(建议 30s 间隔)
  • connectSocket() 中 phone.hello 发送后不检查结果
  • project.pbxproj 手写 ID(功能不影响,但 Xcode 保存后会重写造成 diff 噪声)
  • NSAllowsLocalNetworking = true 正确,未过度放开 ATS ✅

与 Android #342 对比

维度 iOS (#341) Android (#342)
WebSocket 重连 ❌ 无 ✅ 线性退避
角色选择 ❌ 始终 first ✅ 点击选中
发指令前校验 ❌ 无 ✅ 空值拦截
协议编解码 内联 ViewModel ✅ 独立 Codec + 测试
单元测试 ❌ 无 ✅ 4 用例
错误日志 ❌ 无 ✅ Log.e
Authorization ❌ 都缺失 ❌ 都缺失

合并建议

Request Changes。主要原因:缺 Authorization header(功能缺陷)、无重连(体验断崖)、合并冲突。修复此三项后可合。

@xiaocui-big xiaocui-big left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

平台组正式 Review(崔泽生)

详细分析见上方评论。总结三个合并阻塞项:

  1. 缺 Authorization Bearer Token — api-contract-v0.md §1 要求 Authorization: Bearer <boot-token>,PhoneSession.swift 的 loadOrg() 和 pair() 均未设置,对真实主机会 401
  2. 无 WebSocket 重连 — 网络抖动只能手动重新配对,Android 端已有指数退避
  3. 合并冲突 — mergeable: CONFLICTING,CHANGELOG.md 冲突需 rebase

修复此三项后可合。

@waterbro-8

Copy link
Copy Markdown
Collaborator Author

技术纠正与合并阻塞更新:

  1. 不要给 iOS 客户端加入 boot token,也不要让配对接口下发 boot token。 api-contract-v0.md 的 Bearer 约束适用于本机控制面;移动端路线走托管的 phone-link.v1 relay。feat(mobile): phone shell and phone-link command channel #357 已明确:

    • POST /phone-link/v1/pair 用 6 位配对码换取设备凭据;
    • WebSocket 首帧用 deviceToken;
    • /api/mobile/workspace 读取 relay 的组织快照;
    • 控制面仍绑定 127.0.0.1,手机不接触 boot token。

    因此原 review 的 Authorization blocker 应替换为:feat(ios): SwiftUI native RoleWeave client (#338) #341 显式依赖 feat(mobile): phone shell and phone-link command channel #357 的 host/relay 契约落地。在 feat(mobile): phone shell and phone-link command channel #357 未合并且自身尚有冲突/CI 失败时,feat(ios): SwiftUI native RoleWeave client (#338) #341 不能被视为端到端可用,但修法不是扩大 boot token 暴露面。

  2. 其余合并阻塞仍成立:

    • rebase main 并解决冲突;
    • WebSocket 断线后做有上限的指数退避重连;
    • 发送前必须显式选择岗位,缺失时 fail closed,不能默认 roles.first;
    • 配对码发送前校验为恰好 6 位数字;
    • 补协议解析/URL 构造单测,并加入可实际编译/运行测试的 iOS CI。

@AppStorage、心跳和日志可作为同批体验完善,但不改变上述安全边界。修复后请由独立 reviewer 对最终 head 重新提交正式 review。

waterbro-8 added a commit that referenced this pull request Sep 18, 2026
Address xiaocui-big review on roleweave #341: send Authorization on HTTP, reconnect WebSocket with backoff, require an explicit role, validate 6-digit pair codes, persist host/boot-token, and rebase CHANGELOG onto main 0.3.0.
@waterbro-8

Copy link
Copy Markdown
Collaborator Author

已按 @xiaocui-big 平台组 Review 改到 head 81dc0b6:

  1. Authorization:loadOrg() / pair() 在有 boot-token 时发送 Authorization: Bearer <boot-token>;指令页和设置页可填,本地持久化。401 会提示需要 boot-token。
  2. WebSocket 重连:断开后指数退避 1s/2s/4s/8s/16s,最多 5 次,保留 device token,不再立刻 paired = false。
  3. CHANGELOG:按当前 main 的 [0.3.0] 重写 Unreleased,只保留 feat(ios): SwiftUI native RoleWeave client #338 本 PR 条目,冲突应消失。
  4. 岗位:组织页必须显式点选;sendCommand 不再取 roles.first;未选中则拒绝发送。
  5. 配对码:仅 6 位数字。
  6. 抽出 PhoneLinkCodec(URL / hello / command / backoff / 鉴权头)。Linux 上仍无法跑 Xcode 单测。

请复审 #341

Resolve CHANGELOG conflict with current main (Android #339 already landed). Keep iOS-only files under mobile/ios plus the three-app README.
@waterbro-8

Copy link
Copy Markdown
Collaborator Author

Cleanup after 胡奕舟 2026-09-19 09:21「你们的 pr 清理一下」.

Rebased onto current main 8d26ff0 (new head aa53e0d). CHANGELOG conflict with landed Android #339 resolved; mobile/android and mobile/harmony on main are untouched. iOS files remain under mobile/ios.

Please re-review the iOS client on this head. I cannot self-approve CODEOWNERS.

@waterbro-8

Copy link
Copy Markdown
Collaborator Author

已按平台组阻塞项补齐:HTTP 请求带 Bearer boot-token、WebSocket 1/2/4/8/16 秒且最多 5 次退避并保留 device token、6 位数字配对码、组织页显式选岗位后才可发送。已同步最新 main;Linux 无法运行 Xcode,待独立复审在 Mac 上编译确认。

@waterbro-8

Copy link
Copy Markdown
Collaborator Author

状态更新:当前 exact head 为 968099d4b03c3053f84c15a31c48855a21a6fd2d(此前评论中的 aa53e0d 已过时)。11 项 CI 全部通过;Linux 无法替代 Xcode/macOS 编译验证,等待独立 reviewer 对该 head 批准。

@PeterGuy326 PeterGuy326 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review on merge head 208695d: all three blockers from the platform review are resolved.

  1. Authorization: PhoneSession now sends Authorization: Bearer <boot-token> on HTTP calls (built in PhoneLinkCodec.swift; /health remains the only unauthenticated route), so pairing and loadOrg work against real hosts.
  2. WebSocket reconnect: exponential backoff 1/2/4/8/16s with max 5 attempts (reconnectDelayMs), on parity with the Android client, preserving the device token.
  3. Branch rebased onto current main with the CHANGELOG entry intact.

Approving; merge will follow once CI is green on this head.

@PeterGuy326
PeterGuy326 merged commit b77e3f5 into main Sep 19, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(ios): SwiftUI native RoleWeave client

3 participants