Skip to content

WebView2 窗口规范与 API ​

本页说明独立 WebView2 窗口。Framework 同时支持 Studio 内的原生 NGUI 窗口,选型与共同要求见 Mod 窗口开发规范,原生窗口见 NGUI 窗体 API。

Framework 提供 StudioAPI.CreateWebWindow,用于显示 HTML/CSS/JavaScript 开发的 Mod 面板。支持绝对 file://、HTTP 和 HTTPS 地址。

Studio 使用 Unity Mono。Framework 将 Microsoft.Web.WebView2 WinForms 控件放在独立的 Windows .NET Framework x64 宿主中,避免将控件的 COM 互操作依赖加载进 Mono。宿主入口使用 [STAThread],通过 Application.Run 提供消息循环。网页仍使用原生 window.chrome.webview,Framework 自动建立仅当前 Windows 用户可访问的随机命名管道,不占用 TCP 端口。

mermaid
flowchart LR
  Mod[Mod / Unity 主线程] --> SDK[ModWebWindow]
  SDK <-->|自动命名管道 / JSON| Host[独立 .NET WinForms STA 宿主]
  Host <-->|WebMessageReceived / PostWebMessageAsJson| Page[WebView2 网页]
  SDK -->|owner.Update 派发| Mod
  Studio[Studio 进程] -->|退出检测| Host

Mod API ​

在 Unity 主线程、Studio 主窗口创建完毕后调用,通常放在菜单点击回调中。owner 必须为保持激活的 Mod GameObject;隐藏或禁用 owner 会暂停事件派发,销毁 owner 或 Studio 退出会关闭宿主。

csharp
var window = StudioAPI.CreateWebWindow(
    gameObject, "Mod 面板", 800, 600, new Uri(htmlFileAbsolutePath));

window.Ready += delegate {
    window.PostWebMessageAsJson("{\"type\":\"STATE\",\"rpm\":120}");
};
window.MessageReceived += delegate(string json) {
    // 此处已回到 Unity 主线程;解析消息并校验 type、partId、rpm 后调用 Studio API。
    Debug.Log(json);
};
window.Failed += delegate(string error) { Debug.LogError(error); };
window.Closed += delegate { /* 用户关闭窗口或宿主结束 */ };

Ready 表示初始页面完成加载。C# 向网页发消息前需等待此事件;网页可在加载过程中发送消息。所有四个事件均由 Unity 主线程派发。Failed 可能表示初始化/导航失败、进程失败或无效 JSON;无效 JSON 不关闭窗口,初始化/导航失败会关闭窗口。单条消息限 1 MiB,待派发回调最多 256 条,每帧最多派发 64 条,持续超量会结束连接并报告错误。

window.Activate() 将已连接的弹窗带到前台;window.Close() / Dispose() 关闭弹窗,重复调用安全。显式 Dispose 会取消未派发回调,且不触发 Closed。Mod 卸载时应主动 Dispose;owner 销毁也会自动清理。

调用 window.SetIcon(logoPath) 设置窗口标题栏、任务栏和 Alt+Tab 图标。可以在 CreateWebWindow 返回后立即调用,无需等待 Ready,也可以在窗口打开后替换图标。

csharp
string logoPath = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), "logo.ico");
window.SetIcon(logoPath);

支持本地 .ico 和 .png 文件,相对路径以 Studio 进程工作目录解析,建议始终提供 Mod DLL 同目录下的绝对路径。推荐包含 16/32/48/256 像素图层的 ICO;PNG 会转换为 32×32 的 Windows 图标。无需调用此接口也能正常使用窗口。图标格式不支持或文件不存在时,SDK 同步抛出异常;图片损坏或宿主加载失败时,通过 Unity 主线程上的 Failed 事件报告,保留原图标和窗口。新接口需要配套更新 StudioSDK.dll 和 WebView2 宿主。

默认 Studio HWND 为 Process.GetCurrentProcess().MainWindowHandle。如果 Studio 环境返回零或错误的主窗口,可以使用最后一个参数为 IntPtr studioHwnd 的重载;宿主会检查 HWND 是否属于 Studio 进程。

WebView2 窗口使用无 Owner 的独立窗口,并显示任务栏按钮。跨进程 Owner 会自动关联输入队列,焦点切换可能等待 Studio 主线程,因此不建立该绑定。窗口不会自动跟随 Studio 最小化、恢复或保持在 Studio 上层;通信、Mod 资源清理和 Studio 进程退出检测由 Framework 管理。

网页 API ​

javascript
window.chrome.webview.postMessage({ type: 'SET_RPM', partId: 10, rpm: 120 });
window.chrome.webview.addEventListener('message', event => {
  console.log(event.data); // 已解析的 JSON 值
});

网络页面仅允许初始地址的相同协议、主机和端口导航及发送消息;本地页面仅允许初始文件自身(允许 query/hash)。页面内资源仍可正常加载。新窗口请求被取消,Host Objects 接口被禁用。Mod 仅应加载自己信任的页面,并校验业务消息。

完整示例见 examples/webview2/ModWebWindowExample.cs 与 index.html,编译插件后将 HTML 放在插件 DLL 同目录。

构建与部署 ​

需要 Windows x64、.NET Framework 4.7.2+ 和 Evergreen WebView2 Runtime。Windows 11 预装 Runtime,许多 Windows 10 设备也已安装,但必须允许 Runtime 缺失或损坏;Framework 会通过 Failed 报告,用户可从 微软 WebView2 下载页 安装。Framework 不自动安装 Runtime。微软部署说明

build.bat、build.bat internal、build-loader.ps1 和解决方案构建均包含宿主。首次构建从官方 NuGet 源下载固定版本 Microsoft.Web.WebView2 1.0.4258.31,缓存于 deps/WebView2/package;离线构建需预先准备该缓存。SDK 无需引用 WebView2 DLL,Mod 开发者只需引用 StudioSDK.dll。

产物位于 bin/WebView2/(内部包位于 bin/internal/bin/WebView2/),包含宿主 EXE、配置、Core/WinForms DLL、x64 WebView2Loader.dll 和许可证。安装器将该目录部署到 Studio_Data/Managed/WebView2/。手动部署时必须将整个 WebView2 目录放在 StudioSDK.dll 旁;不要将这些 Microsoft 控件 DLL 放到 Mods 根目录供 Unity 加载。用户数据缓存位于 %LOCALAPPDATA%/Studio 2.0/WebView2/Profile。

powershell
./tests/run-webview2-tests.ps1
./tests/run-webview2-tests.ps1 -Integration

集成测试需要已安装 Runtime 和桌面会话,使用实际 WinForms HWND、宿主和 WebView2 页面验证无 Owner、窗口独立性、双向 JSON、主线程派发、错误及关闭清理。Studio 内还应人工对比焦点切换延迟,并验证 Mod 卸载和 Studio 退出行为。

为 BrickLink Studio 2.0 打造的第三方 Mod 加载框架 · 与 BrickLink / LEGO 官方无关联