> For the complete documentation index, see [llms.txt](https://tinyhumans.gitbook.io/openhuman/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tinyhumans.gitbook.io/openhuman/zh/gong-neng/ios-companion.md).

# iOS 配套应用

iOS Companion 让你可以用手机连接桌面端的 OpenHuman：你在桌面上扫描显示的二维码，两台设备协商出一把共享密钥，此后手机便通过加密通道与桌面核心通信。

{% hint style="warning" %}
**实验性 / 不随正式版发布。** iOS 客户端仍在开发中，并且 **不** 属于已发布的桌面产品。API、线协议格式以及配对流程都可能在未通知的情况下变更，升级后可能会强制你重新配对。请将下面内容视为开发者预览。
{% endhint %}

桌面核心始终是事实来源。手机只是一个轻客户端。它不运行自己的代理，而是把请求转发给核心并渲染结果。

***

## 它是什么

配对由 Rust `devices` 域在核心中进行协调。核心会向 tinyhumans 后端的 `tunnel:*` Socket.IO 中继注册一个配对通道，生成一对新的 X25519 密钥对，并渲染一个二维码。手机扫描后，生成 **自己的** X25519 密钥对，并通过同一个中继连接回去。后端是一个 **盲转发器**：它转发不透明的数据帧，且从不看到明文。

配对完成后，该设备会显示在 **设置 → 设备** 中，旁边带有在线/离线状态点，并且可随时撤销。

***

## 通过二维码配对

```
桌面核心                         后端中继              iOS 应用
     |                                     |                        |
     |-- devices_create_pairing RPC        |                        |
     |-- tunnel:register ----------------->|                        |
     |<-- channel_id, expires_at ----------|                        |
     |-- generate X25519 keypair           |                        |
     |-- tunnel:connect (role: core) ----->|                        |
     |                                     |                        |
     |   显示二维码:                        |                        |
     |   cid, pt, cpk, rpc?, exp           |                        |
     |.................. 扫描二维码 ......................>            |
     |                                     |   生成设备的          |
     |                                     |   X25519 密钥对        |
     |                                     |<-- tunnel:connect ------|
     |                                     |    (role: client)       |
     |<------ tunnel:frame (handshake) ----|------------------------|
     |-- X25519 DH + derive session keys   |                        |
     |-- persist PairedDevice              |                        |
     |-- publish DevicePaired event        |                        |
     |   设备出现在 Devices 列表中        |                        |
```

二维码载荷（作为一个 `openhuman://pair?...` 深度链接承载）包含通道 ID（`cid`）、一次性配对令牌（`pt`）、核心的公钥（`cpk`）、可选的局域网 URL（`rpc`）以及过期时间（`exp`）。配对令牌只能使用一次，在后端落盘时会进行哈希处理；一旦 `exp` 已过，客户端就会拒绝该二维码（后端会强制执行真实的约 10 分钟 TTL）。

***

## 端到端隧道

机密性和完整性完全由两端负责。具体原语位于 `src/openhuman/security/devices/crypto.rs`:

* **密钥协商：** X25519 Diffie-Hellman。双方各自拥有一对长期静态密钥对（核心的密钥对会显示在二维码中；设备的密钥对在扫描时生成），另外每个会话还会生成一对临时密钥对，以提供前向保密。
* **会话密钥派生：** 对 `ikm = static_dh || eph_dh`进行 HKDF-SHA256，并使用 `client_eph_pub || server_eph_pub`作为盐。随后用不同的 info 标签扩展出两把 **单向的** 32 字节子密钥（`openhuman-tunnel/v1/c2s` 以及 `openhuman-tunnel/v1/s2c`），因此一端封装的帧绝不可能使用它自己的开启端解密（从而消除了跨方向反射攻击这一类问题）。
* **帧加密：** XChaCha20-Poly1305（AEAD，192 位 nonce）。线协议格式为 `version(0x02) || nonce(24) || ciphertext+tag`，每个帧使用随机 nonce。
* **重放保护：** 针对每个开启端维护最近 128 个 nonce 的滑动窗口。

静态 DH 通过二维码来源来认证对端；临时 DH 则意味着即使之后静态密钥泄露，也无法解密过去的流量。旧版单密钥 `version=0x01` 帧格式会以明确的“需要重新配对”错误被拒绝，因此升级后双方必须重新配对。外发帧大小上限为 64 KB。

***

## 传输策略

手机可以通过三种方式连接到核心。 `TransportManager` (`app/src/services/transport/`）会从已保存的 `ConnectionProfile`中选择一种；对于已配对设备，它会 **让局域网与隧道同时竞争** （2 秒局域网超时），并使用先响应 `openhuman.ping` 的那个。

| 策略                                 | 类                             | 使用场景                              | 权衡                                                           |
| ---------------------------------- | ----------------------------- | --------------------------------- | ------------------------------------------------------------ |
| **局域网 HTTP** (`LanHttpTransport`)  | 直接通过 HTTP 连接到核心的局域网 `rpc_url` | 手机和桌面处于同一网络                       | 速度最快，延迟最低。需要在同一局域网内；这一层不加密（依赖本地网络信任）。                        |
| **隧道** (`TunnelTransport`)         | 通过后端 Socket.IO 中继传输端到端加密帧     | 任何可联网的地方；默认回退方案                   | 可跨网络工作；端到端使用 X25519 + XChaCha20-Poly1305。延迟更高（经由中继）；依赖后端可用性。 |
| **云端 HTTP** (`CloudHttpTransport`) | 通过云端托管的核心端点进行 HTTP 访问         | 配置文件 `kind: "cloud"`，当局域网和隧道都不可用时 | 可从任何地方访问；依赖托管核心及其自身认证。                                       |

***

## 设备管理与撤销

配对设备由核心持久化到 SQLite（`{workspace_dir}/devices/devices.db`，表 `paired_devices`）：通道 ID、标签、设备公钥、核心会话令牌的 SHA-256 哈希以及时间戳。核心的 X25519 私钥在静态存储时会被加密保存（通过 OS keyring `SecretStore`）因此重启后握手仍可继续。

* **List**: `devices_list` 会返回未撤销的设备，并叠加一个实时的 `peer_online` 标志，该标志来源于 `tunnel:peer-status` （在线状态从不持久化保存）。
* **Revoke**: `devices_revoke` 会软删除该设备，清除该通道所有内存中的状态和隧道状态，并发布一个 `DeviceRevoked` 事件。当前的撤销仅发生在本地：后端通道会等待其配对令牌 TTL 到期后自然失效（后端撤销接口会在后续补上）。

***

## 另请参阅

* [隐私与安全](/openhuman/zh/gong-neng/privacy-and-security.md)：OpenHuman 如何处理你的数据和密钥。
* [语音](/openhuman/zh/gong-neng/native-tools/voice.md)：按住说话和听写，是手机伴侣的核心使用场景。
