iOSアプリ(ノード)

公開状況:内部プレビュー段階。iOSアプリはまだ一般公開されていません。

機能概要

  • WebSocket経由でGatewayに接続(LANまたはテールネット)。
  • ノード機能を提供:Canvas、スクリーンスナップショット、カメラキャプチャ、位置情報、トークモード、Voice Wake。
  • node.invokeコマンドを受信し、ノードステータスイベントを報告。

必要条件

  • 別のデバイス(macOS、Linux、またはWindows WSL2)でGatewayが稼働していること。
  • ネットワーク経路:
    • Bonjour経由の同一LAN、または
    • ユニキャストDNS-SD経由のテールネット(ドメイン例:openclaw.internal.)、または
    • ホスト/ポートの手動指定(フォールバック)。

クイックスタート(ペアリング+接続)

  1. Gatewayを起動:
openclaw gateway --port 18789
  1. iOSアプリの設定画面を開き、検出されたGatewayを選択するか、手動ホストを有効にしてホスト/ポートを入力。

  2. Gatewayホストでペアリングリクエストを承認:

openclaw devices list
openclaw devices approve <requestId>
  1. 接続を確認:
openclaw nodes status
openclaw gateway call node.list --params "{}"

公式ビルド向けリレーベースのプッシュ通知

公式配布のiOSビルドは、生のAPNsトークンをGatewayに渡す代わりに、外部プッシュリレーを使用します。

Gateway側の設定:

{
  gateway: {
    push: {
      apns: {
        relay: {
          baseUrl: "https://relay.example.com",
        },
      },
    },
  },
}

フローの仕組み:

  • iOSアプリはApp Attestとアプリレシートを使ってリレーに登録。
  • リレーは不透明なリレーハンドルと登録スコープの送信権限を返す。
  • iOSアプリはペアリング済みGatewayのアイデンティティを取得し、リレー登録に含めることで、その特定のGatewayにリレーベース登録を委譲。
  • アプリはpush.apns.registerでリレーベース登録をペアリング済みGatewayに転送。
  • Gatewayはそのリレーハンドルをpush.test、バックグラウンドウェイク、ウェイクナッジに使用。
  • Gatewayのリレーベース URLは、公式/TestFlightのiOSビルドに組み込まれたリレーURLと一致する必要がある。
  • アプリが別のGatewayや異なるリレーベースURLのビルドに接続すると、古いバインディングを再利用せずリレー登録を更新。

このパスでGatewayが不要なもの:

  • デプロイメント全体のリレートークン。
  • 公式/TestFlightのリレーベース送信用の直接APNsキー。

想定される運用フロー:

  1. 公式/TestFlightのiOSビルドをインストール。
  2. Gatewayでgateway.push.apns.relay.baseUrlを設定。
  3. アプリをGatewayにペアリングし、接続完了まで待つ。
  4. APNsトークン取得後、オペレーターセッション接続済みかつリレー登録成功後に、アプリが自動的にpush.apns.registerを発行。
  5. 以降、push.test、再接続ウェイク、ウェイクナッジは保存済みのリレーベース登録を使用可能に。

互換性に関する注意:

  • OPENCLAW_APNS_RELAY_BASE_URLはGatewayの一時的な環境変数オーバーライドとして引き続き使用可能。

認証と信頼フロー

リレーは、直接APNs-on-Gatewayでは公式iOSビルドに対して提供できない2つの制約を適用するために存在します:

  • ホスティングされたリレーを使用できるのは、Apple経由で配布された正規のOpenClaw iOSビルドのみ。
  • Gatewayがリレーベースのプッシュを送信できるのは、そのGatewayとペアリングしたiOSデバイスに対してのみ。

ホップごとの詳細:

  1. iOSアプリ -> Gateway

    • アプリはまず通常のGateway認証フローでペアリング。
    • これにより認証済みノードセッション+認証済みオペレーターセッションが確立。
    • オペレーターセッションはgateway.identity.getの呼び出しに使用。
  2. iOSアプリ -> リレー

    • アプリはHTTPS経由でリレー登録エンドポイントを呼び出し。
    • 登録にはApp Attentの証明+アプリレシートを含む。
    • リレーはバンドルID、App Attest証明、Appleレシートを検証し、公式/本番の配布パスを要求。
    • ローカルXcode/開発ビルドがホスティングリレーを使えない理由はここにある。ローカルビルドは署名されていても、リレーが求める公式Apple配布証明を満たさない。
  3. Gatewayアイデンティティの委譲

    • リレー登録前に、アプリはgateway.identity.getからペアリング済みGatewayのアイデンティティを取得。
    • アプリはそのGatewayアイデンティティをリレー登録ペイロードに含める。
    • リレーはそのGatewayアイデンティティに委譲されたリレーハンドルと登録スコープの送信権限を返す。
  4. Gateway -> リレー

    • Gatewayはpush.apns.registerからのリレーハンドルと送信権限を保存。
    • push.test、再接続ウェイク、ウェイクナッジの際に、Gatewayは自身のデバイスアイデンティティで送信リクエストに署名。
    • リレーは保存された送信権限と、登録時に委譲されたGatewayアイデンティティに対するGateway署名の両方を検証。
    • 別のGatewayがハンドルを取得しても、その保存済み登録を再利用することはできない。
  5. リレー -> APNs

    • リレーは本番APNs認証情報と公式ビルドの生APNsトークンを所有。
    • Gatewayはリレーベースの公式ビルドでは生APNsトークンを保存しない。
    • リレーはペアリング済みGatewayに代わって最終プッシュをAPNsに送信。

この設計の理由:

  • 本番APNs認証情報をユーザーのGatewayに置かないため。
  • 公式ビルドの生APNsトークンをGatewayに保存しないため。
  • ホスティングリレーの使用を公式/TestFlightのOpenClawビルドに限定するため。
  • あるGatewayが別のGatewayのiOSデバイスにウェイクプッシュを送るのを防ぐため。

ローカル/手動ビルドは直接APNsのまま。リレーなしでこれらのビルドをテストする場合、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(LAN)

Gatewayはlocal._openclaw-gw._tcpをアドバタイズします。iOSアプリはこれらを自動的にリスト表示します。

テールネット(ネットワーク越え)

mDNSがブロックされている場合は、ユニキャストDNS-SDゾーン(ドメインを選択、例:openclaw.internal.)とTailscaleスプリットDNSを使用します。 CoreDNSの設定例はBonjourを参照してください。

手動ホスト/ポート

設定画面で手動ホストを有効にし、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ホストは/__openclaw__/canvas//__openclaw__/a2ui/を配信。
  • Gateway HTTPサーバー(gateway.portと同じポート、デフォルト18789)から配信。
  • iOSノードはCanvasホスト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"}'

Voice Wake+トークモード

  • Voice Wakeとトークモードは設定画面で利用可能。
  • iOSはバックグラウンドオーディオを一時停止する場合があるため、アプリが非アクティブ時の音声機能はベストエフォートとして扱ってください。

よくあるエラー

  • NODE_BACKGROUND_UNAVAILABLE:iOSアプリをフォアグラウンドにしてください(canvas/camera/screenコマンドはフォアグラウンドが必要)。
  • A2UI_HOST_NOT_CONFIGURED:GatewayがCanvasホストURLをアドバタイズしていません。Gateway設定canvasHostを確認してください。
  • ペアリングプロンプトが表示されない:openclaw devices listを実行して手動で承認してください。
  • 再インストール後に再接続できない:キーチェーンのペアリングトークンがクリアされています。ノードを再ペアリングしてください。

関連ドキュメント