跳到主要内容

Chromium Embedded Framework

OpenHuman 不运行平台内置的 webview。它通过 tauri-runtime 的一个分支运送自己的 Chromium Embedded Framework (CEF) 运行时,而这个单一决定几乎是 OpenHuman 产品中每个"OpenHuman 知道您的工具中发生了什么"功能的承载基础。

为什么用 CEF 而不是 stock webview

Stock Tauri 使用每个平台的原生 webview。macOS 上的 WKWebView、Windows 上的 WebView2、Linux 上的 WebKitGTK。这些对渲染 OpenHuman 应用本身很好。但它们有一个致命的限制:它们都不暴露 Chrome DevTools Protocol (CDP)

CDP 是承载原语。OpenHuman 中每个"观察 Slack / WhatsApp / Telegram / Discord / Meet 内部发生了什么"功能都通过 CDP 与这些嵌入式应用对话,而不是通过注入的 JavaScript。CDP 提供:

  • Target.getTargets 发现每个页面和服务 worker
  • IndexedDB.requestDatabaseNames / requestDatabase / requestData 遍历第三方应用的本地存储
  • DOMSnapshot.captureSnapshot 用于只读 DOM 检查,不会触发框架响应性
  • Runtime.evaluate 用于临时一次性读取

CEF 今天用于什么

嵌入式第三方 webviews

每个作为托管 web 应用运行的连接提供商都有自己的子 CEF webview:

  • WhatsApp Web
  • Telegram Web
  • Slack
  • Discord
  • Google Meet
  • LinkedIn
  • Gmail
  • Zoom

CDP 驱动的扫描器

每个提供商都有一个扫描器模块。每个扫描器持有到 CEF 的长寿命 WebSocket(--remote-debugging-port=19222)并按固定时间表 tick:

扫描器频率做什么
whatsapp_scanner2s DOM tick + 30s 全 IDB walk读取消息存储,拉取媒体元数据
telegram_scanner相同加上 QR 登录交接到原生 Telegram Desktop
slack_scanner30s IDB walk纯 IDB - 无需 DOM 抓取
discord_scanner周期性通过 CDP 的频道 + DM 状态
meet_scanner周期性通话期间实时字幕 + 参与者状态

Google Meet 吉祥物相机

Meet agent 不仅参加会议,它还广播自己作为相机。这之所以可行是因为 CEF 允许我们:

  1. 通过 Page.addScriptToEvaluateOnNewDocument 在任何 Meet 代码运行之前注入一个小桥接
  2. 覆盖 navigator.mediaDevices.getUserMedia 以返回来自隐藏 640×480 画布的 MediaStream
  3. 在该画布上渲染吉祥物 SVG,通过 CDP 从 Rust 驱动 window.__openhumanSetMood(...)

"无新 JS 注入"规则

规则在 CLAUDE.md 中文档化:迁移的提供商加载零注入 JavaScript。所有抓取都通过扫描器端的 CDP 原生进行。

提供商已迁移?
WhatsApp✅ 零 JS
Telegram✅ 零 JS
Slack✅ 零 JS
Discord✅ 零 JS
browserscan✅ 零 JS
Gmail遗留 runtime.js 桥接
LinkedIn遗留 LINKEDIN_RECIPE_JS
Google Meet相机 + 音频 + 字幕桥接

CEF 预热

隐藏的 CEF webview(cef-prewarm)在应用启动时启动浏览器,这样当用户点击时第一个子 webview 会立即生成。

Linux shell 回退

在某些 Linux 桌面上(尤其是 NVIDIA 专有驱动程序设置),Tauri/CEF shell 可能在原生窗口配置期间失败。当核心本身健康时,您可以通过单独运行核心和前端来继续开发:

cargo build --bin openhuman-core
./target/debug/openhuman-core run --port 7788

# 另一终端
cd app
pnpm dev

在常规浏览器中打开 Vite URL,选择 Advanced / remote core 模式,将 RPC URL 设置为 http://127.0.0.1:7788/rpc

下一步