从 BlueBubbles 迁移到 OpenClaw 官方 iMessage 插件:配置翻译、群组注册表陷阱与切换验证指南
2026/9/13 6:01:15 网站建设 项目流程

从 BlueBubbles 迁移到 OpenClaw 官方 iMessage 插件:配置翻译、群组注册表陷阱与切换验证指南

【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 🦞项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw

本篇指南面向仍在使用旧版channels.bluebubbles配置的 OpenClaw 用户,完整讲解如何将旧配置翻译为官方@openclaw/imessage插件的channels.imessage配置,包括配置键映射表、imsg的本地验证流程、群组双重闸门(sender allowlist + group registry)的工作原理,以及切换后的逐项验证方法。读完本文,你将能够在不依赖任何 BlueBubbles 服务器的情况下,把 iMessage 通道平稳迁移到基于imsg的原生方案,并定位迁移中最常见的"群组静默"问题。

背景:BlueBubbles 已被移除

OpenClaw 不再内置 BlueBubbles 通道。iMessage 支持只通过官方@openclaw/imessage插件提供,该插件驱动steipete/imsg,其中明确指出:唯一的迁移路径就是把channels.bluebubbles配置迁移到channels.imessage,没有其他受支持的迁移途径。在当前版本 OpenClaw 中,遗留的channels.bluebubbles配置块是惰性的——没有任何运行时读取它。

架构上的核心变化是:一个 CLI 二进制替代了 BlueBubbles 的"服务器 + 客户端 App + webhook 管线"整套组件。旧方案有 REST 端点、有 webhook 鉴权密码;新方案没有任何 HTTP 服务器、没有 webhook URL、没有后台守护进程、没有 launch agent、也没有需要暴露的端口。

imsg是什么:JSON-RPC over stdio

imsg是一个运行在登录了 Messages.app 的 Mac 上的本地 CLI。OpenClaw Gateway 以子进程方式启动imsg rpc,通过标准输入/输出(stdin/stdout)以换行分隔的 JSON-RPC 2.0 协议通信。从插件源码 extensions/imessage/src/client.ts 可以看到,IMessageRpcClient.start()使用spawn(cliPath, ["rpc", "--json"])拉起子进程,并用一个 LF 帧解析器逐行读取 stdout 上的 JSON 响应、把 stderr 诊断写入运行时日志。

imsg的各条数据路径分工如下:

  • 读取:来自~/Library/Messages/chat.db,使用只读 SQLite 句柄。
  • 实时入站:来自imsg watch/watch.subscribe,它监听chat.db的文件系统事件,并带轮询兜底。
  • 发送:普通文本和文件发送走 Messages.app 自动化(AppleScript/AppleEvents)。
  • 高级动作:使用imsg launchimsghelper 注入 Messages.app,从而解锁已读回执、正在输入指示器、富文本发送、编辑、撤回、线程回复、tapback、投票和群组管理。

需要特别说明平台限制:Linux 构建可以读取拷贝过来的chat.db,但无法发送、无法 watch 实时 Mac 数据库、也无法驱动 Messages.app。因此 OpenClaw iMessage 必须让imsg运行在已登录的 Mac 上,或者通过 SSH wrapper 转发到那台 Mac。

关于桥接健康还有一个值得注意的实现细节:源码 extensions/imessage/src/private-api-status.ts 维护了按cliPath键控的 private API 状态缓存。当imsg自身的结构化等待错误(Timed out waiting for response to ...)表明桥接卡死时,extensions/imessage/src/client.ts 会先失效缓存,再调用 extensions/imessage/src/bridge-recovery.ts 自动执行一次imsg launch重新注入 dylib,同时刻意不重放失败的那次发送——因为imsg可能已经完成了发送,重放会导致消息重复。

迁移检查清单

如果你已经清楚旧 BlueBubbles 配置,最短的安全路径如下:

  1. openclaw plugins install @openclaw/imessage安装官方插件,然后重启 Gateway。
  2. 在运行 Messages.app 的 Mac 上直接验证imsgimsg chatsimsg historyimsg sendimsg rpc --help)。
  3. 把行为类配置键从channels.bluebubbles复制到channels.imessagedmPolicyallowFromgroupPolicygroupAllowFromgroupsincludeAttachmentsattachmentRootsmediaMaxMbtextChunkLimitactions
  4. 丢弃不再存在的传输类配置键:serverUrlpassword、webhook URL 以及 BlueBubbles 服务器相关设置。
  5. 如果 Gateway 不在 Messages Mac 上运行,把channels.imessage.cliPath设置为 Gateway 本地、指向 SSH wrapper 的绝对路径,并让dbPath保持为该 Mac 上的绝对路径;复杂 wrapper 场景下把remoteHost设为 Messages Mac 的主机名或user@host。OpenClaw 会自动识别简单的透明 wrapper 形态以保持兼容。
  6. 启用channels.imessage,重启 Gateway,然后运行openclaw channels status --probe --channel imessage
  7. 测试一条 DM、一个获准的群组、按需测试附件,以及你期望 agent 使用的每一个私有 API 动作。
  8. 确认 iMessage 路径可用后,删除 BlueBubbles 服务器和旧的channels.bluebubbles配置块。

一个已知的远程限制需要注意:远程imsgv0.13.4 有两个狭窄的 RPC 限制——投票必须使用pollOptionId而不能用下标或选项文本;附件回复不能指向非零的消息片段下标。本地imsg行为不受影响。

开始之前:安装与验证imsg

1. 在运行 Messages.app 的 Mac 上安装imsg

brew install steipete/tap/imsg brew update && brew upgrade imsg imsg --version imsg chats --limit 3

对于常规本地部署,OpenClaw setup 可以在已登录的 Messages Mac 上提供经用户确认的 Homebrew 安装或更新。手动安装和 SSH wrapper 拓扑仍需运维自行管理:务必在实际运行imsg的那个本地或远程用户上下文里重复 Homebrew 更新。

如果imsg chatsunable to open database file、返回空输出或authorization denied,需要给启动imsg的终端、编辑器、Node 进程、Gateway 服务或 SSH 父进程授予完全磁盘访问权限(Full Disk Access),然后重新打开该父进程。

2. 修改 OpenClaw 配置前,先验证读、watch、发送和 RPC 四个面

imsg chats --limit 10 --json | jq -s imsg history --chat-id 42 --limit 10 --attachments --json | jq -s imsg watch --chat-id 42 --reactions --json imsg send --chat-id 42 --text "OpenClaw imsg test" imsg rpc --help

42替换为imsg chats输出的真实 chat id。发送需要 Messages.app 的自动化(Automation)权限。如果 OpenClaw 通过 SSH 运行,请用同样的 SSH wrapper 或用户上下文执行这些命令。如果读取正常但发送报 AppleEvents-1743,请检查 Automation 权限是否落到了/usr/libexec/sshd-keygen-wrapper上,详见 iMessage 文档 中的权限说明。

3. 启用私有 API 桥接(强烈建议)

imsg launch imsg status --json

imsg launch要求关闭 SIP(现代 macOS 上还需要放宽库验证,见 iMessage 文档)。基本的发送、历史记录和 watch 不需要imsg launch也能工作,但 OpenClaw iMessage 的完整动作面(回复、tapback、特效、投票、附件回复、群组动作)依赖它。

4. 启用channels.imessage并启动 Gateway 后,通过 OpenClaw 验证桥接

openclaw channels status --probe

iMessage 账户应报告works;加--json时,probe 负载中应包含privateApi.available: true。如果报告false,先修复这个问题(见 iMessage 文档 的能力检测章节)。注意:probe 需要 Gateway 可达(否则 CLI 退化为仅输出配置),并且只探测已配置、已启用的账户。

5. 快照你的配置

cp ~/.openclaw/openclaw.json ~/.openclaw/openclaw.json.bak

配置翻译:逐键对照表

iMessage 与 BlueBubbles 共享大部分通道级行为键,变化的是传输层(REST 服务器 → 本地 CLI)和群组注册表的键格式。

BlueBubblesiMessage 插件说明
channels.bluebubbles.enabledchannels.imessage.enabled语义相同(配置块存在时默认true)。
channels.bluebubbles.serverUrl(已移除)没有 REST 服务器——插件在 stdio 上拉起imsg rpc
channels.bluebubbles.password(已移除)无需 webhook 鉴权。
(隐式)channels.imessage.cliPathimsg路径(默认imsg);SSH 场景用指向 Gateway 主机上 wrapper 的绝对路径。
(隐式)channels.imessage.dbPath可选的chat.db覆盖路径;SSH 场景下是 Messages Mac 上的绝对路径,绝不会相对 Gateway 家目录展开。
(隐式)channels.imessage.remoteHostMessages Mac,格式为hostuser@host;显式配置优先,简单的透明 SSH wrapper 每个进程自动检测一次。用于通过严格 SSH/SCP 拉取入站附件与执行仅属主出站暂存。清理是尽力而为,失败会告警并可能残留属主文件。
channels.bluebubbles.dmPolicychannels.imessage.dmPolicy取值相同(pairing/allowlist/open/disabled),默认pairing
channels.bluebubbles.allowFromchannels.imessage.allowFromhandle 格式相同(+15555550123user@example.com)。配对存储中的审批不会迁移,见下文。
channels.bluebubbles.groupPolicychannels.imessage.groupPolicy取值相同(allowlist/open/disabled),默认allowlist
channels.bluebubbles.groupAllowFromchannels.imessage.groupAllowFrom相同。未设置时 iMessage 回退到allowFrom;显式设置groupAllowFrom: []会在groupPolicy: "allowlist"下拦截所有群消息。
channels.bluebubbles.groupschannels.imessage.groups原样复制"*"通配项;按数字 iMessagechat_id重新键控逐群条目——见"群组注册表陷阱"。requireMentiontoolstoolsBySendersystemPrompt原样继承。
channels.bluebubbles.sendReadReceiptschannels.imessage.sendReadReceipts默认true,仅在私有 API probe 通过后生效。
channels.bluebubbles.includeAttachmentschannels.imessage.includeAttachments结构相同,同样默认关闭。如果 BlueBubbles 时代有附件流动,请显式开启——否则入站照片/媒体会被静默丢弃(日志里连Inbound message行都不会有)。
channels.bluebubbles.attachmentRootschannels.imessage.attachmentRoots本地根目录,通配规则相同。
(N/A)channels.imessage.remoteAttachmentRoots仅在设置remoteHost时用于 SCP 拉取。
channels.bluebubbles.mediaMaxMbchannels.imessage.mediaMaxMbiMessage 默认 16 MB(BlueBubbles 默认 8 MB)。想保持低上限就显式设置。
channels.bluebubbles.textChunkLimitchannels.imessage.textChunkLimit两者默认都是 4000。
channels.bluebubbles.coalesceSameSenderDms(已移除)不要迁移这个键。imsg0.13.1 及更新版本会在 OpenClaw 收到消息前合并 Apple 的 URL 预览拆分发送;openclaw doctor --fix会移除过期的 iMessage 键。
channels.bluebubbles.enrichGroupParticipantsFromContacts(N/A)imsg已从chat.db提供发送者显示名。
channels.bluebubbles.actions.*channels.imessage.actions.*逐动作开关相同(reactionseditunsendreplysendWithEffectrenameGroupsetGroupIconaddParticipantremoveParticipantleaveGroupsendAttachment),外加新增的polls。全部默认启用;私有 API 动作仍要求桥接可用。

多账户配置(channels.bluebubbles.accounts.*)一对一翻译为channels.imessage.accounts.*

从源码看,这些键在 extensions/imessage/src/config-schema.ts 中均有对应的 Zod schema 约束:actions是带 12 个布尔开关的严格对象;remoteHost通过isSafeScpRemoteHost校验(只接受 SSH host 或user@host,不含空格/选项);cliPathExecutableTokenSchemagroups是记录类型(record),每个条目可携带requireMention、工具策略等选项。dmPolicy的取值约束通过refineChannelDmPolicy应用到通道级与每个账户级。

群组注册表陷阱:双重闸门

iMessage 插件对群消息连续执行两道闸门,必须同时通过消息才会到达 agent:

  1. 发送者 / 会话目标 allowlistchannels.imessage.groupAllowFrom)——匹配发送者 handle 或会话目标(chat_id:chat_guid:chat_identifier:条目)。groupAllowFrom未设置时回退到allowFrom;显式groupAllowFrom: []则禁用回退,并在groupPolicy: "allowlist"下丢弃所有群消息。
  2. 群组注册表channels.imessage.groups)——以数字 iMessagechat_id为键:
    • 没有groups块(或为空):只要闸门 1 的有效发送者 allowlist 非空,群消息就通过本闸门,由发送者过滤控制访问,且不会触发 drop-all 启动告警。
    • groups有条目但没有"*":只有列出的chat_id键能通过。只要列出了任何群,注册表就变成 allowlist,即使groupPolicy: "open"也一样
    • groups: { "*": { ... } }:所有群都通过本闸门。

迁移陷阱就在这里:BlueBubbles 用 chat GUID / chat identifier 作为groups条目的键,而 iMessage 注册表用数字chat_id。逐条照抄的 per-group 条目会形成一个非空注册表,但键永远匹配不上,于是每条群消息都在闸门 2 被丢弃。正确做法:"*"通配项原样复制;具体群条目用imsg chats返回的chat_id重新键控。

两条丢弃路径在默认日志级别下都可见,均为warn行:

  • 每个账户在启动时打印一次——当groupPolicy: "allowlist"且有效群发送者 allowlist 为空时:imessage: groupPolicy="allowlist" for account "<id>" but no group sender allowlist is configured ...。设置groupAllowFrom(或allowFrom)来放行发送者;单独添加groups不能满足发送者闸门
  • 每个chat_id在运行时打印一次——注册表丢弃某群时:imessage: dropping group message from chat_id=<id> ... not in channels.imessage.groups allowlist,并明确指出需要添加的键。

注意:DM 无论怎样都正常工作——它们走的是另一条代码路径,所以 DM 成功并不能证明群组路由正常。

groupPolicy: "allowlist"下的最小发送者作用域配置:

{ channels: { imessage: { groupPolicy: "allowlist", groupAllowFrom: ["+15555550123", "chat_guid:any;-;..."], }, }, }

这会放行配置中的发送者进入任何群。如需限定允许的会话或设置requireMention等 per-chat 选项,再添加groups条目;BlueBubbles 的"*"条目原样复制,具体条目用数字chat_id重新键控。群策略的运行时解析实现见 extensions/imessage/src/group-policy.ts,它通过 SDK 的buildChannelGroupsScopeTree构建作用域树,再解析requireMention与工具策略。

逐步切换

  1. 翻译配置。编辑期间保持新块禁用;旧的channels.bluebubbles块会被当前 OpenClaw 忽略,可以留着作参考:

    { channels: { imessage: { enabled: false, // 就绪后翻成 true 即可切换 cliPath: "/opt/homebrew/bin/imsg", dmPolicy: "pairing", allowFrom: ["+15555550123"], // 从 bluebubbles.allowFrom 复制 groupPolicy: "allowlist", groupAllowFrom: [], // 从 bluebubbles.groupAllowFrom 复制 groups: { "*": { requireMention: true } }, // 通配项原样复制;per-chat 条目按 chat_id 重新键控 // actions 默认全部启用;需要禁用的动作显式设为 false }, }, }
  2. 切换并探测。设置channels.imessage.enabled: true,重启 Gateway,确认通道健康:

    openclaw gateway restart openclaw channels status --probe --channel imessage # 期望 "works";--json 显示 privateApi.available: true

    probe 要求 Gateway 可达,且只探测已配置、已启用的账户。用上面"开始之前"里的imsg直接命令验证 Mac 本身。

  3. 验证 DM。给 agent 发一条私信,确认回复到达。

  4. 单独验证群组。DM 和群组走不同代码路径——DM 成功不能证明群组在路由。在获准的群聊里发一条消息,确认回复到达。如果群组静默(无 agent 回复、无报错),去 gateway 日志查上面"群组注册表陷阱"提到的两条warn行:启动告警意味着有效发送者 allowlist 为空;per-chat_id告警意味着已填充的groups注册表不包含该会话。

  5. 验证动作面。从已配对的 DM 中,让 agent 依次执行:点按回应(react)、编辑、撤回、回复、发送照片,以及在群里重命名群组或添加/移除成员。每个动作都应原生落在 Messages.app 中。如果某动作抛出iMessage <action> requires the imsg private API bridge,重新运行imsg launch并用openclaw channels status --probe刷新能力检测。

  6. 删除 BlueBubbles 服务器和channels.bluebubbles配置块,前提是 iMessage 的 DM、群组和动作都已验证。OpenClaw 不读取channels.bluebubbles

动作平价一览

动作旧 BlueBubblesiMessage 插件
发送文本 / SMS 回退
发送媒体(照片、视频、文件、语音)
线程回复(reply_to_guid
点按回应(react
编辑 / 撤回(macOS 13+ 接收方)
带屏幕特效发送
富文本粗体 / 斜体 / 下划线 / 删除线✅(通过 attributedBody 的 typed-run 格式化)
原生 Messages 投票(创建与投票)✅(actions.polls;接收方需 iOS/macOS 26+ 才能原生渲染)
重命名群组 / 设置群图标
添加 / 移除成员、退出群组
已读回执与正在输入指示✅(以私有 API probe 通过为前提)
Apple URL 预览拆分发送合并✅(由imsg0.13.1 及更新版本在上游处理,无 OpenClaw 配置项)
重启后的入站恢复✅(自动:since_rowid重放 + GUID 去重;本地场景窗口更宽)

重启后的入站恢复值得展开:Gateway 宕机期间错过的消息会在启动时自动补回——通过imsg watch.subscribesince_rowid从最后已分发的 rowid 重放,按 GUID 去重,并用过期积压年龄围栏(stale-backlog age fence)抑制 Apple 在 Push 恢复后可能冲刷的"积压炸弹"。这个机制跑在imsgRPC 连接之上,因此远程 SSHcliPath部署同样生效;本地部署因为能直接读chat.db,恢复窗口更宽。详见 iMessage 文档。

配对、会话与 ACP 绑定

  • allowlist 按 handle 原样继承。channels.imessage.allowFrom识别与 BlueBubbles 相同的+15555550123/user@example.com字符串,直接原样复制。
  • 配对存储中的审批不会迁移。配对存储是按通道隔离的,没有任何机制迁移旧 BlueBubbles 存储。仅通过配对获得审批的发送者需要在 iMessage 下重新配对一次,或者你把这些 handle 加入allowFrom
  • 会话保持按 agent + 会话隔离。默认session.dmScope=main下 DM 折叠进 agent 主会话;默认session.groupScope="per-group"下群会话按chat_id隔离(agent:<agentId>:imessage:group:<chat_id>)。BlueBubbles 会话键下的旧对话历史不会进入 iMessage 会话。
  • ACP 绑定中引用match.channel: "bluebubbles"的必须改成"imessage"match.peer.id的形状(chat_id:chat_guid:chat_identifier:、裸 handle)完全一致。

没有回滚通道

不存在可以切回的受支持 BlueBubbles 运行时。如果 iMessage 验证失败,处理方式是把channels.imessage.enabled: false、重启 Gateway、修复imsg阻塞点,然后重试切换。

回复缓存保存在 SQLite 插件状态里。openclaw doctor --fix会在旧imessage/reply-cache.jsonlsidecar 存在时将其导入并归档。

相关文档

  • BlueBubbles removal and the imsg iMessage path — 移除公告与运维摘要。
  • iMessage — 完整 iMessage 通道参考,包括imsg launch配置与能力检测。
  • Pairing — DM 鉴权与配对流程。
  • Channel routing — Gateway 如何为出站回复选择通道。
  • 插件包说明见 extensions/imessage/README.md:插件 idimessage,包名@openclaw/imessage,最低 OpenClaw 主机版本2026.7.2;RPC 超时默认值(probe 10 秒、发送 180 秒)见 extensions/imessage/src/constants.ts。

【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 🦞项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询