openclaw/docs/platforms/ios.md
Chris Herold 6e33f3f0f3
iOS: implement dual-connection gateway architecture with deadlock fix
Aligns the iOS app with the Clawnet refactor by implementing proper role
separation for gateway connections. Uses separate operator and node sessions
to match the gateway's authorization requirements.

Changes:
- New GatewayOperatorSession: Wraps GatewayChannelActor for operator-role
  RPC requests (chat.*, health, sessions.list) without invoke handling
- Dual-connection architecture: Operator session for requests, node session
  for node.event calls (e.g., chat.subscribe)
- Separate websocket sessions: Each connection gets its own URLSession to
  prevent response cross-talk
- Updated chat transport: IOSGatewayChatTransport uses operator session for
  requests, node session for subscriptions

ClawdbotKit (shared):
- Deadlock fix in GatewayChannel.swift: Moved connection finalization
  (listen(), connected=true, isConnecting=false, waiter resumption) to occur
  before calling pushHandler. This fixes a latent bug where requests made
  from onConnected callbacks would deadlock. Does not affect macOS (its
  callback doesn't make requests).
- Package.swift: Fixed argument order for Swift 6.2 compatibility

iOS chat is now working. This is the base PR to unlock further work on
the iOS app.
2026-01-27 14:46:27 -08:00

129 lines
4.5 KiB
Markdown

---
summary: "iOS node app: connect to the Gateway, pairing, canvas, and troubleshooting"
read_when:
- Pairing or reconnecting the iOS node
- Running the iOS app from source
- Debugging gateway discovery or canvas commands
---
# iOS App (Node)
Availability: internal preview. The iOS app is not publicly distributed yet.
## What it does
- Connects to a Gateway over WebSocket (LAN or tailnet).
- Exposes node capabilities: Canvas, Screen snapshot, Camera capture, Location, Talk mode, Voice wake.
- Receives `node.invoke` commands and reports node status events.
## Requirements
- Gateway running on another device (macOS, Linux, or Windows via WSL2).
- Network path:
- Same LAN via Bonjour, **or**
- Tailnet via unicast DNS-SD (`moltbot.internal.`), **or**
- Manual host/port (fallback).
## Quick start (authenticate + pair + connect)
### 1. Start the Gateway
```bash
moltbot gateway --port 18789
```
### 2. Configure authentication in the iOS app
Open Settings in the Moltbot iOS app and configure **one** of the following:
- **Gateway Token**: Paste the token from `moltbot config get gateway.token` (recommended for secure setups)
- **Gateway Password**: Enter the password from `moltbot config get gateway.password` (simpler alternative)
If neither is set on the gateway, you can set one:
```bash
moltbot config set gateway.token "your-secret-token"
# or
moltbot config set gateway.password "your-password"
```
### 3. Select the gateway
In the iOS app Settings, pick a discovered gateway from the list, or enable **Manual Host** and enter the host/port manually.
### 4. Approve the pairing request
The iOS app requires device pairing for both operator and node roles. On the gateway host, list and approve pending devices:
```bash
moltbot devices list
moltbot devices approve <id>
```
You may need to approve twice (once for operator role, once for node role).
> **Note**: Use `moltbot devices` for WebSocket pairing, not `moltbot nodes pending/approve`.
### 5. Verify connection
```bash
moltbot nodes status
moltbot gateway call node.list --params "{}"
```
## Discovery paths
### Bonjour (LAN)
The Gateway advertises `_moltbot._tcp` on `local.`. The iOS app lists these automatically.
### Tailnet (cross-network)
If mDNS is blocked, use a unicast DNS-SD zone (recommended domain: `moltbot.internal.`) and Tailscale split DNS.
See [Bonjour](/gateway/bonjour) for the CoreDNS example.
### Manual host/port
In Settings, enable **Manual Host** and enter the gateway host + port (default `18789`).
## Canvas + A2UI
The iOS node renders a WKWebView canvas. Use `node.invoke` to drive it:
```bash
moltbot nodes invoke --node "iOS Node" --command canvas.navigate --params '{"url":"http://<gateway-host>:18793/__moltbot__/canvas/"}'
```
Notes:
- The Gateway canvas host serves `/__moltbot__/canvas/` and `/__moltbot__/a2ui/`.
- The iOS node auto-navigates to A2UI on connect when a canvas host URL is advertised.
- Return to the built-in scaffold with `canvas.navigate` and `{"url":""}`.
### Canvas eval / snapshot
```bash
moltbot nodes invoke --node "iOS Node" --command canvas.eval --params '{"javaScript":"(() => { const {ctx} = window.__moltbot; 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\"; })()"}'
```
```bash
moltbot nodes invoke --node "iOS Node" --command canvas.snapshot --params '{"maxWidth":900,"format":"jpeg"}'
```
## Voice wake + talk mode
- Voice wake and talk mode are available in Settings.
- iOS may suspend background audio; treat voice features as best-effort when the app is not active.
## Common errors
- `NODE_BACKGROUND_UNAVAILABLE`: bring the iOS app to the foreground (canvas/camera/screen commands require it).
- `A2UI_HOST_NOT_CONFIGURED`: the Gateway did not advertise a canvas host URL; check `canvasHost` in [Gateway configuration](/gateway/configuration).
- **Authentication failed**: Ensure the gateway token or password in iOS Settings matches what is configured on the gateway (`moltbot config get gateway.token` or `gateway.password`).
- **Pairing prompt never appears**: Run `moltbot devices list` to see pending requests and approve with `moltbot devices approve <id>`.
- **Reconnect fails after reinstall**: The Keychain pairing token was cleared; re-pair the device using `moltbot devices list` and `moltbot devices approve`.
## Related docs
- [Pairing](/gateway/pairing)
- [Discovery](/gateway/discovery)
- [Bonjour](/gateway/bonjour)