Unity Embedded Browser文档翻译
这个资产可以将谷歌浏览器的开源核心部分嵌入到Unity
一. 快速开始
基础用法:
-
将 ZFBrowser 导入到你的项目中。
-
找到
ZFBrowser/Prefabs/Browser (Mouse)
预制体,把它拖到场景里。 -
在新生成的对象上,把 URL 设置为任意你想访问的网站,比如
https://google.com/
。 -
调整你的相机,让这个 quad(平面) 填满大部分视野。
-
点击 Play 并与网站进行交互。
嵌入式资源:
-
以上面的场景为基础。
-
在你的 Assets 文件夹旁边(而不是里面)创建一个文件夹,命名为 BrowserAssets。
-
在 BrowserAssets 文件夹下新建一个
index.html
文件,并写入以下内容:<h1>Hello World!</h1>
-
把浏览器的 URL 设置为
localGame://index.html
。 -
点击 Play。
-
恭喜!你现在在游戏里拥有了一个浏览器!
二. 通用说明
✅ 支持的平台
此插件支持以下平台和架构:
-
Windows 独立版
-
32 位(Mono)和 64 位(Mono 或 il2cpp)
-
不包括 WSA/UWP/HoloLens 支持
-
如果系统没有安装基本更新,可能无法运行
-
不支持 Windows XP
-
-
Linux 独立版(实验性)
-
仅 64 位(Mono)
-
最新的 Ubuntu LTS 应该可以正常工作
-
如果发现主流的近期发行版有问题,请反馈
-
Unity 2018.3.0 以及部分 2018.3.x 版本无法运行,请使用 Unity 2018.3.8+
-
-
OS X 独立版
-
仅 64 位(Mono 或 il2cpp)
-
不包括 Mac App Store 支持
-
说明:
-
除特别说明外,只支持在目标平台上进行构建。
-
如果你在打包或编辑器中测试遇到问题,建议在目标平台的 Unity 编辑器上重试。
🎥 编解码器限制
该资源包 不包含专有或专利相关的编解码器(例如 h.264)。
-
大多数流媒体网站使用专利相关的编解码器,因此无法播放。
-
YouTube 视频通常可以播放,除非是直播。
-
如果需要播放,请考虑使用 Chromium 支持的开源编解码器重新编码,例如 WebM 或 Ogg Vorbis。
🍏 OS X 用户说明
-
在 Unity 2017.3 之前,新建项目默认会构建为 Universal(通用架构),你需要改为 x64 才能正常构建和运行。
-
你可以在 Windows 上打包 OS X 版本,但要确保传到 Mac 文件系统后,相关文件被设置为可执行:
chmod +x MyGame.app/Contents/MacOS/MyGame chmod +x MyGame.app/Contents/Frameworks/ZFGameBrowser.app/Contents/MacOS/ZFGameBrowser
🐧 Linux 用户说明
-
Linux 支持目前仍是 实验性。
-
你可以在 Windows 上打包 Linux 版本,但要确保传到 Linux 文件系统后,相关文件被设置为可执行:
chmod +x MyGame.x86_64 chmod +x MyGame_Data/Plugins/ZFGameBrowser
-
在新版 Ubuntu 上,需要安装额外依赖:
sudo apt install libgconf2-4
📦 其他平台
目前 ZFBrowser 仅支持上述平台。
三. 脚本使用
你可以在 Unity 中向当前加载的浏览器页面 发送消息 或 接收消息。
📝 JavaScript 与 UnityScript 的区别
-
浏览器运行的是 JavaScript(ECMAScript 标准),扩展名是
.js
。 -
Unity 运行的是 .NET 语言,主要是 C#(.cs),以前也支持 Boo(.boo) 和 UnityScript(.js)。
-
UnityScript 和“JavaScript”是两个独立的事物。
⚠️ 明确:
UnityScript ≠ JavaScript。
在本插件中,所有提到的 “JavaScript” 都是指 浏览器端运行的 JavaScript。
需要注意:
-
放在
Assets/
文件夹下的.js
文件会被 Unity 当作 UnityScript。 -
放在
BrowserAssets/
文件夹下的.js
文件才会被当作 浏览器 JavaScript。
🚀 脚本入门
浏览器对象有一个 Browser MonoBehaviour。
你可以通过 CallFunction
调用页面中的函数:
using ZenFulcrum.EmbeddedBrowser;// 假设当前脚本和 Browser 组件挂在同一个 GameObject 上
var browser = GetComponent<Browser>();// 调用页面中全局函数:window.setPlayerStats("myPlayerName", 2, 4200, false)
browser.CallFunction("setPlayerStats", "myPlayerName", 2, 4200, false).Done();
-
CallFunction
会在浏览器顶层 frame 的全局作用域中解析函数名,并传入参数。 -
可以直接传递字符串、整数、布尔值等基础类型。
🔍 执行任意 JS
你也可以使用 EvalJS
在页面中执行任意 JavaScript:
browser.EvalJS("if (someCondition()) someVar = 42;").Done();
📥 从页面获取数据
EvalJS
和 CallFunction
都是 异步执行,返回一个 Promise。
// 获取页面标题
browser.EvalJS("document.title").Then(ret => Debug.Log("Document title: " + ret)).Done();// 调用函数并获取结果
browser.CallFunction("doSomeFoo", 1, 2, 3).Then(ret => Debug.Log("Result: " + ret)).Done();
在 Unity 协程中,你可以直接等待 Promise 完成:
var promise = browser.EvalJS("document.title");
yield return promise.ToWaitFor();
Debug.Log("Document title: " + promise.Value);
这样在需要串联多个任务时更方便。
⚠️ 错误处理
通常建议在 EvalJS()
或 CallFunction()
后加 .Done()
,这样会自动附加一个错误处理器,记录异常或语法错误。
-
如果不加
.Done()
/.Catch()
等,你的代码仍会执行,但如果失败,你不会收到任何通知。
📤 从页面向 Unity 发送事件
可以通过 RegisterFunction
注册一个回调函数,让页面调用 Unity:
browser.RegisterFunction("confirmClicked", args => Debug.Log("Button clicked: " + args[0] + " val: " + (int)args[1])
);
然后在 HTML 中调用:
<!-- 点击时,Unity 会打印 "Button clicked: button3 val: 13" -->
<button onclick="confirmClicked('button3', 13)">Confirm Things</button>
🧩 数据格式说明
-
从页面返回的数据是 JSONNode,它可以隐式转换为字符串、整数等基础类型。
-
如果要传递更复杂的数据,可以手动构造 JSONNode。
-
如果需要自动序列化/反序列化对象:
-
Unity 侧可以用任何 JSON 库(Unity 自带、Newtonsoft.Json 等)。
-
浏览器端可以用
JSON.stringify
/JSON.parse
。
-
-
也可以直接执行 原始 JavaScript:
browser.EvalJS(...)
。
⚙️ 运行机制说明
-
如果浏览器尚未就绪或页面未加载,它会将命令排队,等页面加载完成后再执行。
-
JS 引擎是 V8,支持现代 JavaScript(es6 等)。
-
注意:你在 Unity 注册的函数在 HTML load 事件触发时还不可用。
-
如果要监听页面加载,使用 Unity 端的
browser.WhenLoaded
。
-
-
如果页面有严格的 Content Security Policy (CSP) 禁止
eval
,可以使用EvalJSCSP
,但要注意其限制。
📌 Promise 库说明
-
使用的是 Real Serious Games 的 Promise 库,稍作修改:
-
命名空间改为
ZenFulcrum.EmbeddedBrowser
,避免冲突。 -
默认注册了
UnhandledException
→ 会通过Debug.LogError
输出。 -
支持和 Unity 协程一起用:
yield return somePromise.ToWaitFor();
。 -
可以通过
promise.Value
获取结果或错误。
-
-
该库基于 MIT 许可证(见 ThirdPartyNotices.txt)。
四. Embedded Resources(嵌入式资源)
你可以把网页资源(HTML、JS、CSS、图片等)和游戏一起打包,并且无需外部 Web 服务器就能访问它们。
方法:
把这些资源放到 BrowserAssets 文件夹(位置:和 Assets
文件夹平级,不是里面),
然后用 localGame://index.html
来访问,而不是传统的 http://example.com/index.html
。
📌 注意事项
-
localGame:// 域名
它被当作一个独立的域名,和正常网站一样受到“同域策略”限制。 -
注入脚本
如果你想在任意网站上运行脚本,可以直接打开该网站,然后用browser.EvalJS("alert('hello');");
来注入 JavaScript。
-
资源加载机制
如果你想自定义或者修改资源的加载方式,可以阅读WebResources.cs
里的文档。 -
编辑器刷新
在 Unity 编辑器中,你只要刷新页面,就能看到修改后的文件。 -
文件名大小写敏感
一定要测试独立构建版本!因为在编辑器里有的平台可能会错误地忽略大小写(例如index.html
和Index.html
都能访问),但打包后会严格区分。 -
打包时
构建时,所有浏览器资源都会被打包成一个单独文件并包含在构建里。 -
localGame:// 并不是实际 URL
它只是对开发者暴露的一个别名,真正浏览器内部用的地址是https://game.local/
(但这个可能会变)。
所以不要在 HTML 内部写死localGame://
。 -
不要放不可信代码
不要把不安全的 JS 或 HTML 放在BrowserAssets
中。 -
路径 URL 编码
如果你的路径里有非字母数字字符(比如中文、空格、特殊符号),可能需要 URL 编码。
✅ 例子(路径编码)
假如你有一个文件:
BrowserAssets/我的页面.html
访问时需要转成:
localGame://%E6%88%91%E7%9A%84%E9%A1%B5%E9%9D%A2.html
五. 输入系统 (Input)
所有 鼠标/键盘输入事件 都由 Unity 收集,然后转发给内置浏览器。输入的发送方式是可以自定义的。
ZFBrowser 内置了几种输入方式:
-
鼠标
-
触摸屏
-
相机射线(FPS 风格)
-
VR 控制器
这些输入系统支持的浏览器渲染方式有:
-
渲染到任意形状的 Mesh(需 Mesh Collider)
-
渲染到 Unity 的 GUI 系统
🖱️ 内置浏览器 Prefab(根据输入选择)
-
Browser (Mouse)
用鼠标点击场景中的 Mesh。-
使用
PointerUIMesh
监听鼠标/触摸事件 -
使用
CursorRendererOS
修改鼠标光标外观
-
-
Browser (FPS)
角色走动 + 相机射线交互。-
使用摄像机前向射线计算指向位置
-
鼠标点击作为输入
-
使用
CursorRendererOverlay
在屏幕中央绘制光标
-
-
Browser (GUI)
在 Canvas GUI 上使用。-
使用
CursorRendererOS
修改鼠标光标 -
建议 Canvas 开启 Pixel Perfect 选项,浏览器显示更清晰
-
-
Browser (VR)
VR 控制器射线交互。-
使用
CursorRendererWorldSpace
在世界坐标绘制光标 -
VR 需要额外配置(见 VR Input 部分)
-
🔍 输入判定机制
-
除了 GUI 模式外,其他模式都依赖 Mesh Collider + 射线 来判断点击位置。
-
Mesh Collider 需要与显示用的 Mesh 保持一致,或者至少 UV 对齐。
🖼️ 光标系统
-
网页会显示不同的鼠标光标(例如文本输入、可点击手型等)。
-
上述 Prefab 已经处理大部分情况。
-
如果你需要自定义,可以研究
CursorRenderer*
系列类。
⚠️ 限制
-
所有点击/触摸目前都会被当作 单一鼠标点击 处理。
-
暂时 不支持触摸滚动/手势。
-
可以用
EvalJS
注入 JavaScript 来绕过限制。 -
鼠标滚轮速度、双击行为可在
myBrowserUI.InputSettings
修改。
🥽 VR 输入
-
需要 Unity 2017.2+。
-
VR 控制器输入通过底层 API 获取,可能需要额外配置。
-
先在 Unity Player Settings → XR Settings 里开启 VR。
-
不同 VR 后端有不同配置方法:
🔹 SteamVR
-
Unity 2018.3+:需要安装 OpenVR 包。
-
两种方式:
-
Option A(SteamVR 1.x,硬编码输入,简单)
-
默认触发器=左键,握把=右键,触摸板/摇杆=滚动
-
-
Option B(SteamVR 2.0+,可重映射输入,复杂)
-
修改
OpenVRConfig.cs
→InputMode.MappedActions
-
导入 SteamVR SDK
-
配置动作绑定,确保
PointPose
和LeftClickAction
存在
-
-
🔹 Oculus VR
-
Unity 2018.3+:安装 Oculus (Standalone) 包。
-
导入 Unity Oculus SDK。
-
在 Player → Scripting Define Symbols 添加
OCULUS_API
。 -
删除
ZFBrowser/Scripts/*.asmdef
(2 个)。 -
可以通过
XRDevice.SetTrackingSpaceType(TrackingSpaceType.RoomScale);
设置为房间尺度坐标系。
🔹 通用 VR 使用步骤
-
拖入 Browser (VR) prefab 到场景
-
拖入 VRBrowserHand prefab(左右手各一个),放在 VR 相机附近
-
确保 VRBrowserHand 和 VR 相机同一父物体
-
确保 VR 相机初始旋转为 0
-
运行 VR demo 测试
⌨️ 外部键盘 (External Keyboard)
-
提供了一个 虚拟键盘(主要用于 VR 环境没有实体键盘时)。
-
可与浏览器绑定,输入会传递到网页。
-
打开
ExternalKeyboard
demo 体验。
功能:
-
基于简化 QWERTY 布局
-
支持文本操作(全选、撤销/重做、剪贴板)
-
支持 Shift + 方向键选择文字
-
有不同主题可切换(点击 ✩ 键)
-
键盘 UI 是
Keyboard.html
(在ZFBrowser/Resources/Browser/
下) -
ExternalKeyboard.cs
负责焦点管理和输入路由
使用方法:
-
拖入
ExternalKeyboard
prefab 到场景 -
默认会自动连接到当前聚焦的浏览器
-
可以在 Inspector 调整绑定方式
六. 自定义功能 (Customization)
ZFBrowser 允许你自定义浏览器的交互界面和行为,包括对话框、错误页面、鼠标光标等。
🔹 自定义对话框
-
你可以通过修改以下文件自定义浏览器内置对话框:
-
ZFBrowser/Resources/Browser/Dialogs.html
-
包括
alert()
、prompt()
、beforeUnload
、密码输入框以及右键菜单(context menu)
-
-
🔹 自定义错误页面
-
通过修改
ErrorGenerator.cs
可以定义自定义错误页面。 -
你还可以监听以下事件:
-
Browser.onLoadError
-
Browser.onCertError
-
Browser.onSadTab
-
🔹 鼠标光标
-
图标资源:
-
存放在
ZFBrowser/Resources/Browser/Cursors.png
-
这些是 Chromium 默认的基础图标
-
-
加载与管理:
-
由
BrowserCursor
类负责加载和管理
-
-
自定义方法:
-
如果只想修改光标外观(不改变大小/映射关系):
-
直接编辑
Cursors.png
-
-
如果需要修改光标大小,或调整光标类型与图标索引的对应关系:
-
需要修改
IconGenerator.cs
-
注意:这个脚本并非面向普通用户,修改起来可能需要深入研究
-
-
七. 调试 (Debugging)
在开发过程中,你经常会需要对网页进行调试。
💡 提示:有时候不需要重启游戏,只要刷新页面即可:
-
方法 1:在 Unity Inspector → 浏览器实例 → 点击 Refresh
-
方法 2:在页面检查器里按 Ctrl + R
🔹 页面检查器 (Page Inspector)
你可以直接使用 Webkit/Chromium 自带的开发者工具,调试窗口会在游戏运行时弹出。
-
在编辑器 Play 模式下:
-
选中 Browser,点击 Show Dev Tools
-
-
代码方式:
browser.ShowDevTools();
🔹 外部调试器 (External Page Inspector)
你也可以用外部浏览器或 IDE 调试页面(基于 Chromium 的调试器)。
-
在 Unity 编辑器中运行时:
访问http://localhost:9848/
-
在 Debug 构建版本运行时:
访问http://localhost:9849/
-
注意:Release 构建版本不支持这种方式。
👉 用 Chromium 内核的浏览器打开上面的地址(最好和 ZFBrowser 使用相同版本的 Chromium,以防兼容性问题)。
🔹 普通浏览器调试 (Ordinary Browser)
你也可以把页面直接在普通浏览器里打开调试:
-
在 HTML/JS 里添加一些日志(log stub),用于记录 Unity ↔ JS 的交互。
-
在浏览器的开发者工具控制台(JavaScript Console)里调用你要测试的函数。
⚡ 总结:
-
快速调试 → 刷新页面
-
深度调试 → Show Dev Tools / localhost 调试端口
-
跨环境调试 → 普通浏览器加载页面 + 控制台手动调用
八. Cookie
1. 默认行为
-
默认情况下,Cookies 和 Profile 数据在运行之间不会保存。
-
如果你希望浏览器记住登录状态、会话信息等,就需要手动指定 Profile 保存路径。
2. 启用 Cookie / Profile 保存
-
在游戏第一次
Update
之前,设置:
BrowserNative.ProfilePath = "MyProfileData"; // 路径可以是 Application.persistentDataPath 之类
-
或者在场景里放一个 BrowserSystemSettings 组件来指定 Profile 保存目录。
这样运行后,Cookies、缓存、浏览器设置等都会持久化保存。
3. Cookie 管理 API
浏览器实例上有个 CookieManager
,可用于操作 Cookies:
-
清除所有 Cookie
browser.CookieManager.ClearAll();
-
获取 Cookies(异步,返回 Promise)
browser.CookieManager.GetCookies().Then(cookies => {foreach (var cookie in cookies) {Debug.Log($"Cookie: {cookie.Name} = {cookie.Value}");}});
-
修改 Cookie
cookie.Value = "newValue";
cookie.Update(); // 更新到浏览器
-
删除 Cookie
cookie.Delete();
-
创建新 Cookie
var cookie = new Cookie(browser.CookieManager);
cookie.Domain = "example.com";
cookie.Name = "session_id";
cookie.Value = "abc123";
cookie.Update(); // 提交
⚠️ 注意:必须至少设置 Domain
、Name
、Value
才能生效。
4. 已知限制
-
除了
ClearAll
之外,其它 Cookie API 还算是实验性的。 -
日期相关(过期时间、创建时间等) 可能有 Bug,可能不会像标准浏览器那样可靠。
九. Notes
1. 页面和界面定制
-
右键菜单:可以自定义哪些元素允许右键菜单,默认只有文本框允许。
-
页面背景:
-
默认
<body>
是透明的。 -
可以通过
Base Color
设置为不透明(在代码中必须在第一次Update()
前设置)。 -
也可以通过 JS 修改背景颜色:
browser.EvalJS("document.body.style.background = 'red'");
-
-
自定义鼠标光标:支持 CSS
cursor
设置。 -
新窗口处理:
-
可以通过 Inspector 或
browser.SetNewWindowHandler
设置:-
Ignore
:忽略新窗口请求。 -
Redirect
(默认):当前窗口跳转到新 URL。 -
NewBrowser
:创建新的游戏内浏览器。 -
NewWindow
:在操作系统新窗口打开,仅用于测试/调试。
-
-
2. 用户代理与 Profile
-
默认使用类似 Chrome 的 User-Agent,并包含应用名和版本。
-
可通过
UserAgent.SetUserAgent(string)
强制设置自定义 UA(需在浏览器初始化前调用)。 -
保存用户数据:
-
通过
BrowserNative.ProfilePath
设置 Profile 路径(第一次初始化前)。 -
也可以用
BrowserSystemSettings
在场景中设置,无需代码。
-
3. 事件与资源管理
-
浏览器会生成多个
ZFGameBrowser
子进程,这是正常现象。 -
可以通过事件监听(如
page load error
)响应页面状态。 -
禁用
Browser
MonoBehaviour 并不会停止浏览器,需要销毁对象或加载空白页面来释放资源。 -
WebRTC 功能可能可用,但不是官方支持,需要命令行开关,注意安全性。
-
不要在项目目录创建
GPUCache
、VideoDecodeStats
、blob_storage
等文件夹,Chromium 会自动管理。
4. 延迟与性能
-
延迟:
-
浏览器渲染在独立进程中,所有点击、JS 调用和输入都是异步处理。
-
会有轻微延迟,不适合节奏游戏或需要低延迟的 UI。
-
-
性能优化:
-
--disable-gpu-vsync
可提高帧率。 -
纹理通常先在 GPU 上合成,再回传 CPU 上传到 Unity。
-
生成 mipmaps 开销大,默认 prefab 使用“模拟 mipmap” shader。
-
对动画或频繁更新的内容,建议用低分辨率纹理;大分辨率适合静态界面。
-
浏览器与 Unity 使用同一 GPU,高分辨率更新会占用显存和带宽。
-
5. 架构特点
-
Chromium 在独立进程中运行,Unity 与其通过 IPC 通信(命名管道 + 共享内存)。
-
游戏运行时会看到
ZFGameBrowser
进程以及 Chromium 子进程,这是正常现象。 -
这样做可以避免 Chromium 与 Unity 之间的兼容问题,并修复很多 Chromium 自身的 bug。
十. Adobe Flash 的实验性支持
1. 基本说明
-
Flash 支持是实验性的,可能未来会移除。
-
Adobe Flash 官方计划在 2020 年底停止支持。
-
使用 Flash 可能会在启动 Flash 内容时闪现一个命令行窗口。
2. 是否需要 Flash?
你只需要 Flash 的情况:
-
显示仅能通过 Flash 播放的内容。
-
播放使用专有编码(如 h.264)的视频:
-
ZFBrowser 默认不支持这些专有编码。
-
Flash 插件可能会提供必要的解码支持。
-
⚠️ 注意:老版本 Flash 可能无法正常运行,用户可能需要手动交互启动内容。
3. 本地开发 / 手动安装 Flash
适用于:仅在自己控制的电脑上开发、测试或分发应用。
步骤:
-
安装 Adobe Flash Player:
-
访问 Adobe Flash Player 历史版本
-
选择操作系统和最新 PPAPI 版本。
-
下载并安装。
-
-
修改
BrowserNative.cs
:-
确保
commandLineSwitches
中有--enable-system-flash
。
-
-
Linux 系统额外参数:
--ppapi-flash-path=/usr/lib/adobe-flashplugin/libpepflashplayer.so --ppapi-flash-version=29.0.0.113
-
路径和版本需替换为实际安装位置和版本。
-
-
重启 Unity 编辑器。
-
每台分发应用的电脑都需要安装 Flash。
4. 分发 Flash
如果要随应用一起分发 Flash:
-
需要 Adobe 授权(获取分发许可)。
-
流程:
-
先按照手动安装方式开发。
-
申请分发许可(填写表格,等待批准)。
-
获取 Adobe 提供的安装程序(PPAPI 版本,用于 Chromium)。
-
配置安装程序随你的应用安装一起运行。
-
总结:
-
Flash 已过时,最好避免使用。
-
只有当目标内容必须依赖 Flash 或专有视频编码时才考虑启用。
-
本地测试可以手动安装,但分发需要 Adobe 授权。