---
read_when:
    - การจับคู่หรือเชื่อมต่อ Node iOS อีกครั้ง
    - การเปิดใช้งานหรือแก้ไขปัญหา Node โดยตรงของ Apple Watch
    - การเรียกใช้แอป iOS จากซอร์สโค้ด
    - การแก้ไขข้อบกพร่องในการค้นหา Gateway หรือคำสั่ง Canvas
summary: 'แอป Node บน iOS: การเชื่อมต่อกับ Gateway การจับคู่ แคนวาส และการแก้ไขปัญหา'
title: แอป iOS
x-i18n:
    generated_at: "2026-07-16T19:23:55Z"
    model: gpt-5.6
    postprocess_version: locale-links-v1
    prompt_version: 32
    provider: openai
    source_hash: 7db2f099602435837cc18fcd3e7670067d4b58b6cdb6f6502704a1565d1d1c61
    source_path: platforms/ios.md
    workflow: 16
---

ความพร้อมใช้งาน: บิลด์แอป iPhone เผยแพร่ผ่านช่องทางของ Apple เมื่อเปิดใช้งานสำหรับรีลีส นอกจากนี้ยังสามารถเรียกใช้บิลด์สำหรับการพัฒนาในเครื่องจากซอร์สได้ด้วย

## การทำงาน

- เชื่อมต่อกับ Gateway ผ่าน WebSocket (LAN หรือ tailnet)
- ให้ความสามารถของโหนด ได้แก่ Canvas, ภาพหน้าจอ, การจับภาพจากกล้อง, ตำแหน่งที่ตั้ง, โหมดสนทนา, การปลุกด้วยเสียง และข้อมูลสรุปสุขภาพแบบเลือกรับ
- รับคำสั่ง `node.invoke` และรายงานเหตุการณ์สถานะของโหนด
- เรียกดูเวิร์กสเปซของเอเจนต์ที่เลือกแบบอ่านอย่างเดียวจากส่วนเอเจนต์ (ไฟล์): เจาะดูไดเรกทอรี แสดงตัวอย่างข้อความพร้อมไฮไลต์ไวยากรณ์ แสดงตัวอย่างรูปภาพ และส่งออกผ่านแผ่นงานการแชร์ ไม่มีการดำเนินการเขียน โดย Gateway จำกัดขนาดของตัวอย่าง
- เก็บแคชออฟไลน์แบบอ่านอย่างเดียวขนาดเล็กสำหรับเซสชันแชทและบทสนทนาล่าสุดแยกตาม Gateway ที่จับคู่ไว้: เมื่อเปิดแบบ cold open จะแสดงบทสนทนาที่ทราบล่าสุดทันทีและรีเฟรชเมื่อ Gateway ตอบกลับ แชทล่าสุดยังเรียกดูได้ขณะตัดการเชื่อมต่อ และการรีเซ็ต/ลืมจะล้างแคชในเครื่องที่มีการป้องกัน
- จัดคิวข้อความที่ส่งขณะตัดการเชื่อมต่อไว้ในกล่องขาออกถาวรแยกตาม Gateway (สูงสุด 50 ข้อความ): บับเบิลที่เข้าคิวจะแสดงในบทสนทนา ส่งตามลำดับเมื่อเชื่อมต่ออีกครั้งพร้อมการลองซ้ำแบบไอดอมโพเทนต์ คงอยู่จนกว่าประวัติมาตรฐานจะยืนยันการส่ง ลองซ้ำโดยเพิ่มช่วงเวลารอก่อนแสดงการดำเนินการลองซ้ำ/ลบ และหมดอายุแทนการส่งหลังออฟไลน์ 48 ชั่วโมง การรีเซ็ต/ลืมจะล้างคิวพร้อมกับแคช
- อ่านข้อความของผู้ช่วยตามคำขอ: กดข้อความในแชทค้างไว้แล้วเลือก **Listen** แอปจะเล่นคลิป `tts.speak` ของ Gateway ที่รองรับด้วยผู้ให้บริการ TTS ที่กำหนดค่าไว้ และใช้เสียงพูดบนอุปกรณ์แทนเมื่อเสียงจาก Gateway ไม่พร้อมใช้งานหรือเล่นไม่ได้ การเล่นจะหยุดเมื่อสลับเซสชันหรือเมื่อแอปทำงานเบื้องหลัง

## ข้อกำหนด

- Gateway ทำงานอยู่บนอุปกรณ์อื่น (macOS, Linux หรือ Windows ผ่าน WSL2)
- เส้นทางเครือข่าย:
  - LAN เดียวกันผ่าน Bonjour **หรือ**
  - Tailnet ผ่าน DNS-SD แบบยูนิแคสต์ (โดเมนตัวอย่าง: `openclaw.internal.`) **หรือ**
  - โฮสต์/พอร์ตที่ระบุด้วยตนเอง (ทางเลือกสำรอง)

## เริ่มต้นอย่างรวดเร็ว (จับคู่ + เชื่อมต่อ)

เมื่อเปิดครั้งแรก แอปจะแสดงคำอธิบายสั้นๆ เกี่ยวกับการจับคู่และหน้า
สิทธิ์ (การแจ้งเตือน กล้อง ไมโครโฟน รูปภาพ รายชื่อ
ปฏิทิน เตือนความจำ ตำแหน่งที่ตั้ง) สิทธิ์ทุกรายการเป็นตัวเลือกและสามารถเปลี่ยนได้
ภายหลังใน **Settings** -> **Permissions** หรือในแอป Settings ของ iOS

1. เริ่ม Gateway ที่มีการยืนยันตัวตนพร้อมเส้นทางที่โทรศัพท์เข้าถึงได้ Tailscale
   Serve คือเส้นทางระยะไกลที่แนะนำ:

```bash
openclaw gateway --port 18789 --tailscale serve
```

สำหรับการตั้งค่าบน LAN เดียวกันที่เชื่อถือได้ ให้ใช้ `gateway.bind: "lan"`
ที่มีการยืนยันตัวตนแทน การผูกกับลูปแบ็กเริ่มต้นไม่สามารถเข้าถึงได้จากโทรศัพท์ หากยัง
ไม่ได้กำหนดค่า Gateway ให้เรียกใช้ `openclaw onboard` ก่อน เพื่อให้การสร้าง
รหัสตั้งค่ามีเส้นทางยืนยันตัวตนด้วยโทเค็นหรือรหัสผ่าน

2. เปิด [UI ควบคุม](/th/web/control-ui) เลือก **Nodes** แล้วคลิก
   **Pair mobile device** ในหน้า **Devices** ขอแนะนำสิทธิ์เข้าถึงแบบเต็ม
   และเลือกไว้เป็นค่าเริ่มต้น ให้เลือกสิทธิ์เข้าถึงแบบจำกัดเฉพาะเมื่อต้องการละเว้น
   การควบคุม Gateway สำหรับผู้ดูแลระบบ จากนั้นคลิก **Create setup code**

3. ในแอป iOS ให้เปิด **Settings** -> **Gateway** สแกนคิวอาร์โค้ด (หรือวาง
   รหัสตั้งค่า) แล้วเชื่อมต่อ

   หากรหัสตั้งค่ามีทั้งเส้นทาง LAN และ Tailscale Serve แอปจะ
   ตรวจสอบตามลำดับและบันทึกปลายทางแรกที่เข้าถึงได้

4. แอปอย่างเป็นทางการจะเชื่อมต่อโดยอัตโนมัติ หาก **Pending approval** แสดง
   คำขอ ให้ตรวจสอบบทบาทและขอบเขตของคำขอก่อนอนุมัติ

   **Settings → Gateway** แสดงว่าการเชื่อมต่อของผู้ดำเนินการที่บันทึกไว้มีสิทธิ์เข้าถึงแบบ
   **Full** หรือ **Limited** การตั้งค่า `ws://` บน LAN แบบข้อความธรรมดาจะถูก
   จำกัดโดยอัตโนมัติเพื่อความปลอดภัยของ bearer token หากถูกจำกัด ให้กำหนดค่า `wss://` หรือ
   Tailscale Serve สแกนรหัสสิทธิ์เข้าถึงแบบเต็มใหม่จาก UI ควบคุมหรือ `openclaw qr`
   จากนั้นเชื่อมต่อใหม่เพื่อเปิดใช้การตั้งค่าและการอัปเกรด

ปุ่ม UI ควบคุมต้องใช้เซสชันที่จับคู่ไว้แล้วซึ่งมี `operator.admin`
หากต้องใช้เทอร์มินัลเป็นทางเลือกสำรอง ให้เลือก Gateway ที่ค้นพบในแอป iOS (หรือเปิดใช้
Manual Host แล้วป้อนโฮสต์/พอร์ต) จากนั้นอนุมัติคำขอบนโฮสต์ Gateway:

```bash
openclaw devices list
openclaw devices approve <requestId>
```

หากแอปลองจับคู่ซ้ำด้วยรายละเอียดการยืนยันตัวตนที่เปลี่ยนไป (บทบาท/ขอบเขต/กุญแจสาธารณะ) คำขอที่รออยู่ก่อนหน้าจะถูกแทนที่และสร้าง `requestId` ใหม่ เรียกใช้ `openclaw devices list` อีกครั้งก่อนอนุมัติ

ตัวเลือกเพิ่มเติม: หากโหนด iOS เชื่อมต่อจากซับเน็ตที่มีการควบคุมอย่างเข้มงวดเสมอ คุณสามารถเลือกใช้การอนุมัติโหนดครั้งแรกโดยอัตโนมัติด้วย CIDR หรือที่อยู่ IP ที่ระบุอย่างชัดเจน:

```json5
{
  gateway: {
    nodes: {
      pairing: {
        autoApproveCidrs: ["192.168.1.0/24"],
      },
    },
  },
}
```

คุณลักษณะนี้ปิดใช้งานโดยค่าเริ่มต้น และใช้เฉพาะกับการจับคู่ `role: node` ใหม่ที่ไม่ได้ร้องขอขอบเขตใดๆ การจับคู่ผู้ดำเนินการ/เบราว์เซอร์ และการเปลี่ยนแปลงบทบาท ขอบเขต เมทาดาทา หรือกุญแจสาธารณะใดๆ ยังคงต้องได้รับการอนุมัติด้วยตนเอง

5. ตรวจสอบการเชื่อมต่อ:

```bash
openclaw nodes status
openclaw gateway call node.list --params "{}"
```

## ข้อมูลสรุปสุขภาพ

โหนด iOS สามารถส่งคืนข้อมูลรวม HealthKit แบบอ่านอย่างเดียวและเลือกรับสำหรับ
วันตามปฏิทินปัจจุบัน ความยินยอมบน iPhone และการอนุญาตคำสั่ง Gateway อย่างชัดเจนเป็น
ด่านที่แยกจากกัน ดูการตั้งค่า วิธีเรียกใช้ ฟิลด์เพย์โหลด พฤติกรรมด้านความเป็นส่วนตัว และการแก้ไขปัญหาได้ที่
[ข้อมูลสรุป HealthKit](/platforms/ios-healthkit)

โดยค่าเริ่มต้น Apple Watch ที่ใช้ร่วมกันจะยังคงใช้รีเลย์ iPhone ที่มีอยู่และ
ไม่จำเป็นต้องจับคู่กับ Gateway แยกต่างหาก จับคู่ Watch กับ iPhone ใน
แอป Watch ของ Apple ติดตั้ง OpenClaw จาก **Watch app -> My Watch -> Available
Apps** จากนั้นเปิด OpenClaw หนึ่งครั้งบนอุปกรณ์ทั้งสอง

## ตรวจสอบการอนุมัติคำสั่ง

การเชื่อมต่อของผู้ดำเนินการที่มี `operator.admin` หรือการเชื่อมต่อ
`operator.approvals` ที่จับคู่ไว้และถูก Gateway กำหนดเป้าหมายอย่างชัดเจน สามารถตรวจสอบ
คำขอเรียกใช้ที่รออยู่บน iPhone ได้ การ์ดอนุมัติจะแสดงตัวอย่างคำสั่งที่ Gateway
ปรับให้ปลอดภัยแล้ว คำเตือน บริบทโฮสต์ เวลาหมดอายุ และเฉพาะ
ตัวเลือกการตัดสินใจที่คำขอนั้นเสนอ Apple Watch ที่จับคู่ไว้จะได้รับ
พรอมต์ที่ปลอดภัยสำหรับผู้ตรวจสอบเดียวกันผ่านรีเลย์ iPhone ที่มีอยู่ และแสดงชุดตัวเลือกแบบย่อ
สำหรับอนุญาตหนึ่งครั้ง/ปฏิเสธ โหมด Gateway โดยตรงของ Watch จะไม่ส่ง
พรอมต์การอนุมัติ

สถานะการอนุมัติใช้ร่วมกับ UI ควบคุมและพื้นผิวแชทที่รองรับ
คำตอบแรกที่ยืนยันแล้วจะมีผล iPhone และ Watch จะดึง
เรกคอร์ดปลายทางมาตรฐานของ Gateway หลังจากพื้นผิวอื่นแก้ไขคำขอ หลังได้รับ
การแจ้งเตือนการแก้ไขจากระยะไกล และเมื่อใดก็ตามที่การรับทราบการแก้ไขอาจ
สูญหาย การดำเนินการจะยังไม่พร้อมใช้งานจนกว่าการอ่านกลับดังกล่าวจะยืนยันว่า
คำขอยังคงรออยู่หรือไม่

ความเป็นเจ้าของการอนุมัติผูกกับ Gateway ที่เลือกไว้ การสลับ Gateway ไม่สามารถ
นำพรอมต์เก่าไปใช้กับการเชื่อมต่อที่มาแทนได้ Gateway ที่มีมาก่อน
เมธอดการอนุมัติแบบรวมจะถอยกลับไปใช้เมธอดเฉพาะสำหรับการเรียกใช้ที่เผยแพร่แล้ว
สถานะปลายทางที่เก็บรักษาไว้และผลลัพธ์ข้ามพื้นผิวที่สมบูรณ์ยิ่งขึ้นต้องใช้
Gateway ที่อัปเดตแล้ว

## โหนด Apple Watch โดยตรงที่เป็นตัวเลือก

โหมดโดยตรงทำให้นาฬิกามีข้อมูลประจำตัวโหนดที่ลงนามแล้วและการเชื่อมต่อ Gateway เป็นของตัวเอง
คำสั่งโหนดที่รองรับจะยังคงทำงานผ่าน Wi-Fi หรือเครือข่ายเซลลูลาร์ของนาฬิกาขณะที่
OpenClaw ทำงานอยู่ แม้ว่า iPhone ที่จับคู่ไว้จะไม่พร้อมใช้งาน

ข้อกำหนด:

- iPhone เชื่อมต่อกับ Gateway โดยมีขอบเขต `operator.admin`
- รหัสตั้งค่าประกาศปลายทาง Gateway แบบ `wss://` พร้อมใบรับรองที่ watchOS เชื่อถือ
  โดยนาฬิกาจะสำรวจต้นทาง `https://` ที่สอดคล้องกัน ไม่รองรับ HTTP แบบข้อความธรรมดาและ
  ใบรับรองที่ลงนามด้วยตนเองหรือการเชื่อถือด้วยลายนิ้วมือเท่านั้น ดูการกำหนดค่าปลายทางได้ที่ [การจับคู่ที่
  Gateway เป็นเจ้าของ](/th/gateway/pairing) เส้นทางลูปแบ็ก เฉพาะ iPhone
  และเฉพาะ tailnet ไม่สามารถเข้าถึงโดยนาฬิกาได้อย่างอิสระ
- การใช้งานเครือข่ายเซลลูลาร์ต้องใช้ Apple Watch ที่รองรับเซลลูลาร์และมีบริการที่ใช้งานอยู่
- OpenClaw ทำงานอยู่บนนาฬิกา Apple ไม่อนุญาตให้แอป watchOS ทั่วไป
  รักษาการเชื่อมต่อ WebSocket/TCP ทั่วไปไว้ ดังนั้นโหนดโดยตรงจึงใช้การสำรวจ HTTPS
  ระยะสั้นและเชื่อมต่อใหม่เมื่อแอปกลับสู่เบื้องหน้า ดู
  [คำแนะนำด้านเครือข่ายระดับต่ำของ watchOS](https://developer.apple.com/documentation/technotes/tn3135-low-level-networking-on-watchOS) จาก Apple

การตั้งค่า:

1. บน iPhone ให้เปิด **Settings -> Apple Watch**
2. แตะ **Enable Direct Gateway Connection**
3. เปิด OpenClaw บนนาฬิกาก่อนรหัสตั้งค่าอายุสั้นจะหมดอายุ
4. ตรวจสอบแถว Apple Watch ที่แยกต่างหากด้วย `openclaw nodes status`

รหัสตั้งค่ามีข้อมูลประจำตัวบูตสแตรปอายุสั้นสำหรับโหนดเท่านั้น ให้ถือว่าเป็น
รหัสผ่านจนกว่าจะหมดอายุ รหัสนี้ไม่มีรหัสผ่านหรือโทเค็น Gateway ที่บันทึกไว้ของ iPhone
หลังการจับคู่ นาฬิกาจะจัดเก็บโทเค็นอุปกรณ์ของตนเองและ
ลบข้อมูลประจำตัวบูตสแตรป โหมดโดยตรงรองรับเฉพาะคำสั่งด้านล่าง
แชท การสนทนา การอนุมัติ และขั้นตอนการแจ้งเตือน `watch.*` ที่มีอยู่ยังคงเป็น
คุณลักษณะรีเลย์ผ่าน iPhone และยังต้องใช้ iPhone ที่จับคู่ไว้

คำสั่งโหนด watchOS โดยตรง:

| พื้นผิว       | คำสั่ง                       | หมายเหตุ                                                   |
| ------------- | ------------------------------ | ------------------------------------------------------- |
| อุปกรณ์        | `device.info`, `device.status` | ข้อมูลประจำตัวนาฬิกา แบตเตอรี่ อุณหภูมิ พื้นที่จัดเก็บ และเครือข่าย |
| การแจ้งเตือน | `system.notify`                | ขณะที่แอปทำงานอยู่ ต้องได้รับสิทธิ์จากนาฬิกา     |

watchOS ไม่เปิดเผย WebKit ให้แอปของบุคคลที่สาม ดังนั้นโหนดนาฬิกาโดยตรง
จึงไม่ประกาศคำสั่ง Canvas

## พุชที่รองรับด้วยรีเลย์สำหรับบิลด์อย่างเป็นทางการ

บิลด์ iOS อย่างเป็นทางการที่เผยแพร่จะใช้รีเลย์พุชภายนอกแทนการเผยแพร่โทเค็น APNs ดิบไปยัง Gateway บิลด์ App Store อย่างเป็นทางการจากช่องทางรีลีสสาธารณะใช้รีเลย์ที่โฮสต์ไว้ที่ `https://ios-push-relay.openclaw.ai` โดย URL ฐานนี้ถูกกำหนดตายตัวสำหรับการเผยแพร่ผ่าน App Store และจะไม่อ่านค่าทดแทนใดๆ

การปรับใช้รีเลย์แบบกำหนดเองต้องใช้เส้นทางการบิลด์/ปรับใช้ iOS ที่แยกออกมาโดยเจตนา ซึ่ง URL รีเลย์ต้องตรงกับ URL รีเลย์ของ Gateway ช่องทางรีลีส App Store จะไม่ยอมรับ URL รีเลย์แบบกำหนดเอง หากใช้บิลด์รีเลย์แบบกำหนดเอง ให้ตั้งค่า URL รีเลย์ของ Gateway ที่ตรงกัน:

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

ลำดับการทำงาน:

- แอป iOS ลงทะเบียนกับรีเลย์โดยใช้ App Attest และ JWS ธุรกรรมแอป StoreKit
- รีเลย์ส่งคืนแฮนเดิลรีเลย์แบบทึบพร้อมสิทธิ์อนุญาตให้ส่งที่จำกัดขอบเขตตามการลงทะเบียน
- แอป iOS ดึงข้อมูลประจำตัวของ Gateway ที่จับคู่ไว้ (`gateway.identity.get`) และรวมไว้ในการลงทะเบียนรีเลย์ เพื่อมอบหมายการลงทะเบียนที่รองรับด้วยรีเลย์ให้แก่ Gateway นั้นโดยเฉพาะ
- แอปส่งต่อการลงทะเบียนที่รองรับด้วยรีเลย์ดังกล่าวไปยัง Gateway ที่จับคู่ไว้ด้วย `push.apns.register`
- Gateway ใช้แฮนเดิลรีเลย์ที่จัดเก็บไว้สำหรับ `push.test` การปลุกเบื้องหลัง และการกระตุ้นให้ตื่น
- หากภายหลังแอปเชื่อมต่อกับ Gateway อื่นหรือบิลด์ที่มี URL ฐานรีเลย์ต่างกัน แอปจะรีเฟรชการลงทะเบียนรีเลย์แทนการนำการผูกเดิมกลับมาใช้

สิ่งที่ Gateway **ไม่** ต้องใช้สำหรับเส้นทางนี้: ไม่ต้องมีโทเค็นรีเลย์ระดับการปรับใช้ และไม่ต้องมีกุญแจ APNs โดยตรงสำหรับการส่งอย่างเป็นทางการผ่าน App Store ที่รองรับด้วยรีเลย์

ลำดับการดำเนินการที่คาดไว้สำหรับผู้ดำเนินการ:

1. ติดตั้งแอป iOS อย่างเป็นทางการ
2. ตัวเลือกเพิ่มเติม: ตั้งค่า `gateway.push.apns.relay.baseUrl` บน Gateway เฉพาะเมื่อใช้บิลด์รีเลย์แบบกำหนดเองที่แยกออกมาโดยเจตนา
3. จับคู่แอปกับ Gateway และปล่อยให้เชื่อมต่อจนเสร็จ
4. แอปจะเผยแพร่ `push.apns.register` เมื่อได้รับโทเค็น APNs เซสชันผู้ดำเนินการเชื่อมต่อแล้ว และการลงทะเบียนรีเลย์สำเร็จ
5. หลังจากนั้น `push.test` การปลุกเพื่อเชื่อมต่อใหม่ และการกระตุ้นให้ตื่น จะสามารถใช้การลงทะเบียนที่รองรับด้วยรีเลย์ซึ่งจัดเก็บไว้ได้

## บีคอนสถานะทำงานในเบื้องหลัง

เมื่อ iOS ปลุกแอปจากการพุชแบบเงียบ การรีเฟรชเบื้องหลัง หรือเหตุการณ์ตำแหน่งที่เปลี่ยนแปลงอย่างมีนัยสำคัญ แอปจะพยายามเชื่อมต่อ Node อีกครั้งเป็นเวลาสั้น ๆ แล้วเรียก `node.event` ด้วย `event: "node.presence.alive"` Gateway จะบันทึกเหตุการณ์นี้เป็น `lastSeenAtMs`/`lastSeenReason` ในข้อมูลเมตาของ Node/อุปกรณ์ที่จับคู่แล้ว หลังจากทราบอัตลักษณ์ของอุปกรณ์ Node ที่ผ่านการตรวจสอบสิทธิ์แล้วเท่านั้น

แอปจะถือว่าการปลุกในเบื้องหลังได้รับการบันทึกสำเร็จก็ต่อเมื่อการตอบกลับจาก Gateway มี `handled: true` Gateway รุ่นเก่าอาจตอบรับ `node.event` ด้วย `{ "ok": true }` การตอบกลับดังกล่าวเข้ากันได้ แต่ไม่นับเป็นการอัปเดตเวลาที่พบล่าสุดแบบคงทน

หมายเหตุด้านความเข้ากันได้:

- `OPENCLAW_APNS_RELAY_BASE_URL` ยังคงใช้เป็นค่าทดแทนชั่วคราวผ่านตัวแปรสภาพแวดล้อมสำหรับ Gateway ได้ (`gateway.push.apns.relay.baseUrl` เป็นแนวทางที่ให้ความสำคัญกับการกำหนดค่าก่อน)
- โหมดพุชของบิลด์รุ่นเผยแพร่บน App Store กำหนดโฮสต์รีเลย์ที่ให้บริการไว้ตายตัวและจะไม่อ่านค่าทดแทน URL ของรีเลย์ — ตัวแปรสภาพแวดล้อมขณะบิลด์ `OPENCLAW_PUSH_RELAY_BASE_URL` มีผลเฉพาะกับโหมดบิลด์ iOS แบบภายในเครื่อง/แซนด์บ็อกซ์เท่านั้น

## ขั้นตอนการตรวจสอบสิทธิ์และความเชื่อถือ

รีเลย์มีไว้เพื่อบังคับใช้ข้อจำกัดสองประการที่การใช้ APNs โดยตรงบน Gateway ไม่สามารถรองรับสำหรับบิลด์ iOS อย่างเป็นทางการได้:

- เฉพาะบิลด์ OpenClaw สำหรับ iOS ของแท้ที่เผยแพร่ผ่าน Apple เท่านั้นที่สามารถใช้รีเลย์ที่ให้บริการได้
- Gateway สามารถส่งการพุชผ่านรีเลย์ได้เฉพาะไปยังอุปกรณ์ iOS ที่จับคู่กับ Gateway นั้นโดยเฉพาะ

แต่ละช่วงการส่งต่อมีดังนี้:

1. `iOS app -> gateway`: แอปจับคู่กับ Gateway ผ่านขั้นตอนการตรวจสอบสิทธิ์ตามปกติของ Gateway ทำให้ได้รับทั้งเซสชัน Node ที่ผ่านการตรวจสอบสิทธิ์และเซสชันผู้ควบคุมที่ผ่านการตรวจสอบสิทธิ์ เซสชันผู้ควบคุมจะเรียก `gateway.identity.get`
2. `iOS app -> relay`: แอปเรียกตำแหน่งข้อมูลการลงทะเบียนของรีเลย์ผ่าน HTTPS พร้อมหลักฐาน App Attest และ JWS ของธุรกรรมแอปจาก StoreKit รีเลย์จะตรวจสอบ ID ของบันเดิล หลักฐาน App Attest และหลักฐานการเผยแพร่ของ Apple รวมทั้งกำหนดให้ต้องเป็นช่องทางการเผยแพร่อย่างเป็นทางการ/สำหรับการใช้งานจริง — สิ่งนี้จะป้องกันไม่ให้บิลด์ Xcode/บิลด์สำหรับการพัฒนาภายในเครื่องใช้รีเลย์ที่ให้บริการ เนื่องจากบิลด์ภายในเครื่องไม่สามารถแสดงหลักฐานการเผยแพร่อย่างเป็นทางการของ Apple ได้
3. `gateway identity delegation`: ก่อนลงทะเบียนรีเลย์ แอปจะดึงอัตลักษณ์ของ Gateway ที่จับคู่แล้วจาก `gateway.identity.get` และรวมไว้ในเพย์โหลดการลงทะเบียนรีเลย์ รีเลย์จะส่งคืนแฮนเดิลรีเลย์และสิทธิ์อนุญาตการส่งที่จำกัดเฉพาะการลงทะเบียน ซึ่งมอบหมายให้แก่อัตลักษณ์ของ Gateway นั้น
4. `gateway -> relay`: Gateway จัดเก็บแฮนเดิลรีเลย์และสิทธิ์อนุญาตการส่งจาก `push.apns.register` เมื่อเกิด `push.test` การปลุกเพื่อเชื่อมต่อใหม่ และการกระตุ้นให้ปลุก Gateway จะลงนามคำขอส่งด้วยอัตลักษณ์อุปกรณ์ของตนเอง รีเลย์จะตรวจสอบทั้งสิทธิ์อนุญาตการส่งที่จัดเก็บไว้และลายเซ็นของ Gateway เทียบกับอัตลักษณ์ Gateway ที่ได้รับการมอบหมายจากการลงทะเบียน Gateway อื่นไม่สามารถนำการลงทะเบียนที่จัดเก็บไว้นั้นกลับมาใช้ได้ แม้จะได้แฮนเดิลมาด้วยวิธีใดก็ตาม
5. `relay -> APNs`: รีเลย์เป็นผู้ดูแลข้อมูลประจำตัว APNs สำหรับการใช้งานจริงและโทเค็น APNs ดิบสำหรับบิลด์อย่างเป็นทางการ Gateway จะไม่จัดเก็บโทเค็น APNs ดิบสำหรับบิลด์อย่างเป็นทางการที่ใช้รีเลย์ รีเลย์จะส่งการพุชขั้นสุดท้ายไปยัง APNs ในนามของ Gateway ที่จับคู่แล้ว

เหตุผลที่สร้างการออกแบบนี้ขึ้นมา: เพื่อเก็บข้อมูลประจำตัว APNs สำหรับการใช้งานจริงไว้นอก Gateway ของผู้ใช้ หลีกเลี่ยงการจัดเก็บโทเค็น APNs ดิบของบิลด์อย่างเป็นทางการบน Gateway อนุญาตให้เฉพาะบิลด์ OpenClaw สำหรับ iOS อย่างเป็นทางการใช้รีเลย์ที่ให้บริการ และป้องกันไม่ให้ Gateway หนึ่งส่งการพุชปลุกไปยังอุปกรณ์ iOS ที่เป็นของ Gateway อื่น

บิลด์ภายในเครื่อง/บิลด์ที่สร้างด้วยตนเองยังคงใช้ APNs โดยตรง หากกำลังทดสอบบิลด์เหล่านั้นโดยไม่ใช้รีเลย์ Gateway ยังคงต้องมีข้อมูลประจำตัว APNs โดยตรง:

```bash
export OPENCLAW_APNS_TEAM_ID="TEAMID"
export OPENCLAW_APNS_KEY_ID="KEYID"
export OPENCLAW_APNS_PRIVATE_KEY_P8="$(cat /path/to/AuthKey_KEYID.p8)"
```

รายการเหล่านี้เป็นตัวแปรสภาพแวดล้อมขณะทำงานของโฮสต์ Gateway ไม่ใช่การตั้งค่า Fastlane โดย `apps/ios/fastlane/.env` จะจัดเก็บเฉพาะข้อมูลการตรวจสอบสิทธิ์ App Store Connect เช่น `APP_STORE_CONNECT_KEY_ID` และ `APP_STORE_CONNECT_ISSUER_ID` เท่านั้น และไม่ได้กำหนดค่าการส่ง APNs โดยตรงสำหรับบิลด์ iOS ภายในเครื่อง

ตำแหน่งจัดเก็บที่แนะนำบนโฮสต์ Gateway ซึ่งสอดคล้องกับข้อมูลประจำตัวของผู้ให้บริการรายอื่นภายใต้ `~/.openclaw/credentials/`:

```bash
mkdir -p ~/.openclaw/credentials/apns
chmod 700 ~/.openclaw/credentials/apns
mv /path/to/AuthKey_KEYID.p8 ~/.openclaw/credentials/apns/AuthKey_KEYID.p8
chmod 600 ~/.openclaw/credentials/apns/AuthKey_KEYID.p8
export OPENCLAW_APNS_PRIVATE_KEY_PATH="$HOME/.openclaw/credentials/apns/AuthKey_KEYID.p8"
```

อย่าคอมมิตไฟล์ `.p8` หรือวางไฟล์ดังกล่าวไว้ภายใต้เช็กเอาต์ของรีโพซิทอรี

## ช่องทางการค้นหา

### Bonjour (LAN)

แอป iOS จะค้นหา `_openclaw-gw._tcp` บน `local.` และเมื่อกำหนดค่าไว้ จะค้นหาโดเมน DNS-SD แบบครอบคลุมพื้นที่เดียวกันด้วย Gateway ที่อยู่ใน LAN เดียวกันจะปรากฏโดยอัตโนมัติจาก `local.` ส่วนการค้นหาข้ามเครือข่ายสามารถใช้โดเมนแบบครอบคลุมพื้นที่ที่กำหนดค่าไว้ได้โดยไม่ต้องเปลี่ยนชนิดบีคอน

### Tailnet (ข้ามเครือข่าย)

หาก mDNS ถูกบล็อก ให้ใช้โซน DNS-SD แบบยูนิแคสต์ (เลือกโดเมน ตัวอย่าง: `openclaw.internal.`) และ DNS แบบแยกเส้นทางของ Tailscale ดูตัวอย่าง CoreDNS ได้ที่ [Bonjour](/th/gateway/bonjour)

### โฮสต์/พอร์ตแบบกำหนดเอง

ใน Settings ให้เปิดใช้ **Manual Host** แล้วป้อนโฮสต์และพอร์ตของ Gateway (ค่าเริ่มต้น `18789`)

## Gateway หลายรายการ

แอปเก็บทะเบียนของ Gateway ทุกตัวที่เคยจับคู่ไว้ จึงสามารถสลับระหว่าง Gateway เหล่านั้นได้โดยไม่ต้องจับคู่ใหม่:

- **Settings -> Gateway** จะแสดงรายการ **Paired Gateways** พร้อมทำเครื่องหมาย Gateway ที่ใช้งานอยู่ แตะรายการเพื่อสลับ แอปจะยุติเซสชันปัจจุบันและเชื่อมต่อกับ Gateway ที่เลือกอีกครั้ง เมนูสลับด่วนจะปรากฏข้างแถวการเชื่อมต่อเมื่อมี Gateway ที่จับคู่ไว้มากกว่าหนึ่งตัว
- ข้อมูลประจำตัว การตัดสินใจด้านความเชื่อถือ TLS การกำหนดค่าตาม Gateway และประวัติการแชตที่แคชไว้จะถูกจัดเก็บแยกตาม Gateway การสลับจะไม่ทำให้สถานะระหว่าง Gateway ปะปนกัน และการลงทะเบียนพุชจะเป็นไปตาม Gateway ที่ใช้งานอยู่
- ปัด Gateway ที่จับคู่แล้ว (หรือใช้เมนูบริบทของรายการนั้น) เพื่อ **Forget** ซึ่งจะลบข้อมูลประจำตัว โทเค็นอุปกรณ์ พิน TLS และแชตที่แคชไว้
- Gateway ที่ค้นพบต้องมองเห็นได้บนเครือข่ายจึงจะสลับไปใช้ได้ ส่วน Gateway แบบกำหนดเองจะเชื่อมต่อใหม่ด้วยโฮสต์และพอร์ตที่บันทึกไว้

## Canvas + A2UI

Node ของ iOS แสดงผล Canvas ด้วย WKWebView ใช้ `node.invoke` เพื่อควบคุม:

```bash
openclaw nodes invoke --node "iOS Node" --command canvas.navigate --params '{"url":"http://<gateway-host>:18789/__openclaw__/canvas/"}'
```

หมายเหตุ:

- โฮสต์ Canvas ของ Gateway ให้บริการ `/__openclaw__/canvas/` และ `/__openclaw__/a2ui/` จากเซิร์ฟเวอร์ HTTP ของ Gateway (พอร์ตเดียวกับ `gateway.port` ค่าเริ่มต้น `18789`)
- Node ของ iOS จะใช้โครงร่างในตัวเป็นมุมมองเริ่มต้นเมื่อเชื่อมต่อ `canvas.a2ui.push` และ `canvas.a2ui.reset` ใช้หน้า A2UI ที่รวมอยู่ในแอปและแอปเป็นเจ้าของ
- หน้า A2UI ของ Gateway ระยะไกลใช้แสดงผลได้อย่างเดียวบน iOS โดยจะยอมรับการทำงานของปุ่ม A2UI แบบเนทีฟเฉพาะจากหน้าที่รวมอยู่ในแอปและแอปเป็นเจ้าของเท่านั้น
- กลับไปยังโครงร่างในตัวด้วย `canvas.navigate` และ `{"url":""}`

## ความสัมพันธ์กับ Computer Use

แอป iOS เป็นพื้นผิว Node บนอุปกรณ์เคลื่อนที่ ไม่ใช่แบ็กเอนด์ Codex Computer Use โดย Codex Computer Use และ `cua-driver mcp` ควบคุมเดสก์ท็อป macOS ภายในเครื่องผ่านเครื่องมือ MCP ส่วนแอป iOS เปิดให้ใช้ความสามารถของ iPhone ผ่านคำสั่ง Node ของ OpenClaw เช่น `canvas.*`, `camera.*`, `screen.*`, `location.*` และ `talk.*`

เอเจนต์ยังสามารถควบคุมแอป iOS ผ่าน OpenClaw ได้โดยเรียกใช้คำสั่ง Node แต่การเรียกเหล่านั้นจะผ่านโปรโตคอล Node ของ Gateway และอยู่ภายใต้ข้อจำกัดการทำงานเบื้องหน้า/เบื้องหลังของ iOS ใช้ [Codex Computer Use](/th/plugins/codex-computer-use) สำหรับการควบคุมเดสก์ท็อปภายในเครื่อง และใช้หน้านี้สำหรับความสามารถของ Node บน iOS

### การประเมินผล / สแนปช็อตของ Canvas

```bash
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\"; })()"}'
```

```bash
openclaw nodes invoke --node "iOS Node" --command canvas.snapshot --params '{"maxWidth":900,"format":"jpeg"}'
```

## การปลุกด้วยเสียง + โหมดสนทนา

- การปลุกด้วยเสียงและโหมดสนทนามีให้ใช้งานใน Settings
- Talk แบบเรียลไทม์ของ OpenAI ใช้ WebRTC ที่ไคลเอนต์เป็นผู้ดูแลเมื่อ `talk.realtime.transport` เป็น `webrtc` ส่วนการกำหนดค่า `gateway-relay` อย่างชัดเจนยังคงอยู่ภายใต้การดูแลของ Gateway ดู [โหมดสนทนา](/th/nodes/talk)
- Node ของ iOS ที่รองรับการสนทนาจะประกาศความสามารถ `talk` และสามารถประกาศ `talk.ptt.start`, `talk.ptt.stop`, `talk.ptt.cancel` และ `talk.ptt.once` ได้ โดยค่าเริ่มต้น Gateway จะอนุญาตคำสั่งกดเพื่อพูดเหล่านั้นสำหรับ Node ที่เชื่อถือได้และรองรับการสนทนา
- iOS อาจระงับเสียงเบื้องหลัง ให้ถือว่าคุณสมบัติด้านเสียงทำงานได้ตามสภาพเมื่อแอปไม่ได้ทำงานอยู่

## ข้อผิดพลาดที่พบบ่อย

- `NODE_BACKGROUND_UNAVAILABLE`: นำแอป iOS มาไว้เบื้องหน้า (คำสั่ง Canvas/กล้อง/หน้าจอจำเป็นต้องใช้แอปในเบื้องหน้า)
- `A2UI_HOST_UNAVAILABLE`: ไม่สามารถเข้าถึงหน้า A2UI ที่รวมมากับแอปใน WebView ของแอปได้ ให้แอปอยู่เบื้องหน้าบนแท็บ Screen แล้วลองอีกครั้ง
- ข้อความแจ้งให้จับคู่ไม่ปรากฏขึ้น: เรียกใช้ `openclaw devices list` แล้วอนุมัติด้วยตนเอง
- Watch ไม่แสดงสถานะ iPhone: ตรวจสอบว่า iPhone รายงาน `watchPaired: true`
  และ `watchAppInstalled: true` ใน `watch.status` หากสถานะการจับคู่เป็นเท็จ ให้จับคู่
  Watch ในแอป Watch ของ Apple หากสถานะการติดตั้งเป็นเท็จ ให้ติดตั้งแอปคู่หู
  จาก **My Watch -> Available Apps** หลังจากเปลี่ยนแปลงอย่างใดอย่างหนึ่งแล้ว ให้เปิด OpenClaw บน
  Watch หนึ่งครั้ง การเข้าถึงได้ทันทีจะยังคงต้องให้ทั้งสองแอปทำงานอยู่
  ส่วนการอัปเดตในคิวสามารถมาถึงภายหลังในเบื้องหลังได้
- การเชื่อมต่อใหม่ล้มเหลวหลังติดตั้งใหม่: โทเค็นการจับคู่ใน Keychain ถูกล้างแล้ว ให้จับคู่ Node ใหม่

## เอกสารที่เกี่ยวข้อง

- [การจับคู่](/th/channels/pairing)
- [การค้นหา](/th/gateway/discovery)
- [Bonjour](/th/gateway/bonjour)
