架构
webview 是三层结构,每层职责清晰、可独立理解。
┌─────────────────────────────────────────────────────────┐
│ App(管理层,单例,UI 线程 COM STA) │
│ ├── 窗口注册表(weak_ptr)+ MRU + 分组 │
│ ├── Worker 线程池(Bridge executor) │
│ ├── message-only HWND(Tray / 快捷键) │
│ ├── taskbar (ITaskbarList3) + 持久化 KV │
│ └── Tray / Menu / Display / dialog / shell │
├─────────────────────────────────────────────────────────┤
│ Window(窗口层,enable_shared_from_this) │
│ ├── Win32 HWND + WebView2 controller │
│ ├── EventBus<WindowEvent / PageEvent> │
│ ├── 几何 / 状态 / 图标 / DevTools / 多屏 │
│ └── Bridge(RPC) │
├─────────────────────────────────────────────────────────┤
│ Bridge(通信层) │
│ ├── envelope 编解码 + args tuple 拆解 + invoke 类型擦除 │
│ ├── send(即发即忘)/ call<T>(同步嵌套泵) │
│ └── reentrancy 检测 │
└─────────────────────────────────────────────────────────┘App — 管理层
App::instance() 单例,跑在 UI 线程(COM STA)。职责:
- 窗口注册表:所有活窗口 weak_ptr + MRU 激活历史 + 分组树
- 线程池:Bridge executor,长任务丢后台,避免阻塞 UI
- 系统集成:Tray、Menu、Display、dialog、shell、clipboard
- taskbar:ITaskbarList3 进度/角标/缩略图
- 持久化:窗口状态 KV
- 生命周期:
run()消息循环、quit()、on(AppEvent)
典型生命周期:
cpp
auto& app = App::instance(); // 进程唯一
app.requestSingleInstanceLock(); // 单实例
auto win = app.createWindow(...);
// ... 注册 RPC / 事件 ...
return app.run(); // 进消息循环,到 quit 退出Window — 窗口层
std::shared_ptr<Window>,封装一个 Win32 HWND + WebView2 controller。每个窗口自带:
- Bridge:该窗口专属的 RPC 通道
- EventBus:WindowEvent(Resize/Move/Close/...)+ PageEvent(DidLoad/TitleChanged/...)
- 几何 / 状态控制:bounds、min/max、aspect、透明、置顶
- 多屏:monitor、moveToDisplay
- DevTools:open/close/executeJavaScript
窗口由 App 创建并登记,close 后从注册表移除。
Bridge — 通信层
JS 与 C++ 之间的 JSON-RPC 风格通道。每个 Window 持有一个 Bridge。
- envelope:固定 JSON 信封(id / channel / args / result / error)
- invoke 类型擦除:
on(name, fn)把任意可调用包成Handler,参数从 JSON 反序列化 call<T>:同步调用,嵌套消息泵等待 JS Promise resolve,带超时与重入死锁检测- send:即发即忘,不等返回
数据流见 RPC 通信。
线程模型
| 线程 | 干什么 |
|---|---|
| UI 线程(主) | COM STA、消息循环、所有 HWND / WebView2 操作、EventBus 派发 |
| Worker 线程池 | Bridge executor 跑 RPC 槽里的耗时任务 |
线程安全
EventBus 仅 UI 线程安全。跨线程触发事件用 App 提供的投递接口,勿直接碰 EventBus。Bridge 槽函数默认在 executor 线程跑,访问窗口 API 时注意回到 UI 线程。
目录结构
include/webview/
app.hpp App 单例
window.hpp Window:控制/几何/事件/Bridge
window_tem.hpp WindowTem 糖衣基类
bridge.hpp RPC:on / call / send
menu.hpp Win32 弹出菜单
tray.hpp 系统托盘
compression.hpp 资源压缩枚举
archive.hpp .7z 解压
value.hpp json 别名 + trait
detail/ envelope / args / invoke / events / mru / pump / strings / js_runtime
src/ 实现
tests/ doctest 单测
docs/guide/ 本文档站(VitePress)
docs/superpowers/ 设计 spec + 实现计划下一步
- RPC 通信:Bridge 细节、调用模式
- WindowTem 模板:Window 之上的声明式糖衣