iOS 应用(节点模式)
状态:内部预览。iOS 应用目前尚未公开分发。
功能概述
- 通过 WebSocket 连接 Gateway(局域网或 tailnet)。
- 暴露节点能力:Canvas、屏幕截图、相机拍摄、位置、Talk mode、语音唤醒。
- 接收
node.invoke命令并上报节点状态事件。
前提条件
- 另一台设备上运行着 Gateway(macOS、Linux 或 Windows WSL2)。
- 网络可达:
- 同一局域网通过 Bonjour,或者
- 通过 Tailnet 使用 unicast DNS-SD(示例域名:
openclaw.internal.),或者 - 手动填写主机/端口(兜底方案)。
快速开始(配对 + 连接)
- 启动 Gateway:
openclaw gateway --port 18789
-
在 iOS 应用中,打开 Settings,选择一个已发现的 Gateway(或开启 Manual Host 手动输入主机/端口)。
-
在 Gateway 主机上批准配对请求:
openclaw devices list
openclaw devices approve <requestId>
- 验证连接:
openclaw nodes status
openclaw gateway call node.list --params "{}"
正式版的 Relay 推送
正式分发的 iOS 构建使用外部推送 relay,而不是把原始 APNs token 暴露给 Gateway。
Gateway 端配置:
{
gateway: {
push: {
apns: {
relay: {
baseUrl: "https://relay.example.com",
},
},
},
},
}
整体流程:
- iOS 应用通过 App Attest 和应用收据向 relay 注册。
- relay 返回一个不透明的 relay handle 和一个注册范围的发送授权。
- iOS 应用获取已配对 Gateway 的身份信息并包含在 relay 注册中,这样注册就被委托给了那个特定的 Gateway。
- 应用通过
push.apns.register将 relay 注册信息转发给已配对的 Gateway。 - Gateway 使用存储的 relay handle 进行
push.test、后台唤醒和唤醒推送。 - Gateway 的 relay base URL 必须与正式/TestFlight iOS 构建中内置的 relay URL 一致。
- 如果应用后来连接到不同的 Gateway 或使用了不同 relay base URL 的构建,会刷新 relay 注册而非复用旧绑定。
在这种模式下 Gateway 不需要:
- 全局 relay token。
- 用于正式/TestFlight relay 发送的直接 APNs 密钥。
运维流程:
- 安装正式/TestFlight iOS 构建。
- 在 Gateway 上设置
gateway.push.apns.relay.baseUrl。 - 将应用与 Gateway 配对,等待连接完成。
- 应用在获得 APNs token、operator 会话连接成功且 relay 注册完成后,自动发布
push.apns.register。 - 之后
push.test、重连唤醒和唤醒推送就能使用已存储的 relay 注册了。
兼容性说明:
OPENCLAW_APNS_RELAY_BASE_URL仍可作为 Gateway 的临时环境变量覆盖。
认证与信任流程
relay 的存在是为了实现两个直接在 Gateway 上放 APNs 无法满足的约束:
- 只有通过 Apple 正式分发的 OpenClaw iOS 构建才能使用托管 relay。
- Gateway 只能为与该 Gateway 配对过的 iOS 设备发送 relay 推送。
逐跳拆解:
-
iOS 应用 -> Gateway- 应用先通过标准 Gateway 认证流程与 Gateway 配对。
- 由此获得经认证的 node 会话和 operator 会话。
- 通过 operator 会话调用
gateway.identity.get。
-
iOS 应用 -> relay- 应用通过 HTTPS 调用 relay 注册接口。
- 注册包含 App Attest 证明和应用收据。
- relay 验证 bundle ID、App Attest 证明和 Apple 收据,且要求正式/生产分发路径。
- 这就是为什么本地 Xcode/开发构建无法使用托管 relay。本地构建虽然有签名,但不满足 relay 要求的正式 Apple 分发证明。
-
Gateway 身份委托- 注册前,应用通过
gateway.identity.get获取已配对 Gateway 的身份信息。 - 应用将该 Gateway 身份包含在 relay 注册载荷中。
- relay 返回的 relay handle 和发送授权都委托给了该 Gateway 身份。
- 注册前,应用通过
-
Gateway -> relay- Gateway 存储来自
push.apns.register的 relay handle 和发送授权。 - 在
push.test、重连唤醒和唤醒推送时,Gateway 用自己的设备身份签名发送请求。 - relay 同时验证存储的发送授权和 Gateway 签名,与注册时委托的 Gateway 身份进行比对。
- 另一个 Gateway 即使获得了该 handle 也无法复用这个注册。
- Gateway 存储来自
-
relay -> APNs- relay 持有正式构建的生产 APNs 凭证和原始 APNs token。
- 对于 relay 支持的正式构建,Gateway 永远不会存储原始 APNs token。
- relay 代表已配对的 Gateway 向 APNs 发送最终推送。
这个设计的初衷:
- 让生产 APNs 凭证远离用户的 Gateway。
- 避免在 Gateway 上存储正式构建的原始 APNs token。
- 只允许正式/TestFlight OpenClaw 构建使用托管 relay。
- 防止一个 Gateway 向属于其他 Gateway 的 iOS 设备发送唤醒推送。
本地/手动构建仍然走直连 APNs。如果你在没有 relay 的情况下测试这些构建,Gateway 还需要直连 APNs 凭证:
export OPENCLAW_APNS_TEAM_ID="TEAMID"
export OPENCLAW_APNS_KEY_ID="KEYID"
export OPENCLAW_APNS_PRIVATE_KEY_P8="$(cat /path/to/AuthKey_KEYID.p8)"
发现方式
Bonjour(局域网)
Gateway 在 local. 上广播 _openclaw-gw._tcp。iOS 应用会自动列出这些服务。
Tailnet(跨网络)
如果 mDNS 不可用,使用 unicast DNS-SD zone(选一个域名,例如 openclaw.internal.)加 Tailscale split DNS。
CoreDNS 配置示例见 Bonjour。
手动填写主机/端口
在 Settings 中,开启 Manual Host 并输入 Gateway 主机 + 端口(默认 18789)。
Canvas + A2UI
iOS 节点通过 WKWebView 渲染 canvas。使用 node.invoke 来控制它:
openclaw nodes invoke --node "iOS Node" --command canvas.navigate --params '{"url":"http://<gateway-host>:18789/__openclaw__/canvas/"}'
说明:
- Gateway canvas host 提供
/__openclaw__/canvas/和/__openclaw__/a2ui/。 - 它由 Gateway HTTP 服务器提供(端口与
gateway.port相同,默认18789)。 - iOS 节点在连接时,如果有 canvas host URL 广播,会自动导航到 A2UI。
- 用
canvas.navigate和{"url":""}回到内置脚手架页面。
Canvas eval / snapshot
openclaw nodes invoke --node "iOS Node" --command canvas.eval --params '{"javaScript":"(() => { const {ctx} = window.__openclaw; ctx.clearRect(0,0,innerWidth,innerHeight); ctx.lineWidth=6; ctx.strokeStyle=\"#ff2d55\"; ctx.beginPath(); ctx.moveTo(40,40); ctx.lineTo(innerWidth-40, innerHeight-40); ctx.stroke(); return \"ok\"; })()"}'
openclaw nodes invoke --node "iOS Node" --command canvas.snapshot --params '{"maxWidth":900,"format":"jpeg"}'
语音唤醒 + Talk mode
- 语音唤醒和 talk mode 在 Settings 中可用。
- iOS 可能在后台挂起音频;应用不在前台时,语音功能只能尽力保证。
常见错误
NODE_BACKGROUND_UNAVAILABLE:把 iOS 应用切到前台(canvas/相机/屏幕命令需要前台)。A2UI_HOST_NOT_CONFIGURED:Gateway 没有广播 canvas host URL;检查 Gateway 配置 中的canvasHost。- 配对提示一直不出现:运行
openclaw devices list手动批准。 - 重装后重连失败:Keychain 中的配对 token 被清除了,需要重新配对。