在Unreal Engine中使用WebBrowser插件时,很多开发者都会遇到一个头疼的问题:我们可以在蓝图中调用JavaScript代码,但却无法从网页直接调用蓝图函数。这就好比两个人打电话,只能一方说话,另一方只能听,这样的沟通效率实在太低了。
我去年开发一个教育类项目时就遇到了这个痛点。项目中需要嵌入一个复杂的在线测试系统,网页端需要实时将用户的答题情况反馈给UE。最初尝试用WebSocket解决,不仅增加了服务器成本,还引入了额外的延迟。后来发现修改WebBrowser插件源码才是最优解,实测下来通信延迟可以控制在5ms以内。
WebBrowser插件底层使用的是CEF(Chromium Embedded Framework),它本质上是一个精简版的Chrome浏览器。当我们在UE中嵌入WebBrowser组件时,实际上是在运行一个独立的浏览器实例。默认情况下,CEF只开放了从宿主程序(UE)到网页的单向通信通道。
首先需要找到引擎自带的WebBrowser插件源码。以UE5.2为例,默认路径是:
code复制D:\Program Files\Epic Games\UE_5.2\Engine\Plugins\Runtime\WebBrowserWidget
把这个目录完整复制到你的项目Plugins文件夹下。这里有个小技巧:我习惯在复制前先创建一个备份分支,这样即使修改出错也能快速回滚。
打开Public/WebBrowser.h文件,在UWebBrowser类声明中添加以下函数:
cpp复制UFUNCTION(BlueprintCallable, Category = "Web Browser")
void BindUObject(const FString& Name, UObject* Object, bool bIsPermanent = true);
这个函数的作用是将UE对象绑定到JavaScript环境中。参数说明:
Name:在JS中访问的对象名称Object:要绑定的UObject实例bIsPermanent:是否永久绑定(建议设为true避免意外释放)在Private/WebBrowser.cpp中添加函数实现:
cpp复制void UWebBrowser::BindUObject(const FString& Name, UObject* Object, bool bIsPermanent)
{
if (WebBrowserWidget.IsValid()) {
WebBrowserWidget->BindUObject(Name, Object, bIsPermanent);
}
}
这里有个坑要注意:一定要先检查WebBrowserWidget是否有效,否则在组件未初始化时调用会导致崩溃。我在第一次实现时就因为这个疏忽浪费了半天时间调试。
修改完成后,关闭UE编辑器,右键点击.uproject文件,选择"Generate Visual Studio project files"。然后用VS打开解决方案,编译整个项目。
ReceiveFromWeb,记得勾选"Callable in Editor"创建一个简单的HTML文件:
html复制<!DOCTYPE html>
<html>
<body>
<button onclick="callUE()">发送消息到UE</button>
<script>
function callUE() {
if(window.ue && window.ue.handler) {
window.ue.handler.ReceiveFromWeb("Hello from Web!");
}
}
</script>
</body>
</html>
当需要传递结构化数据时,建议使用JSON格式。修改ReceiveFromWeb函数:
cpp复制UFUNCTION(BlueprintCallable, Category = "Web")
void ReceiveFromWeb(const FString& JsonData)
{
TSharedPtr<FJsonObject> JsonObject;
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JsonData);
if(FJsonSerializer::Deserialize(Reader, JsonObject)) {
// 解析JSON数据
FString Message = JsonObject->GetStringField("message");
int32 Value = JsonObject->GetIntegerField("value");
}
}
对应的JS调用方式:
javascript复制window.ue.handler.ReceiveFromWeb(JSON.stringify({
message: "Data from web",
value: 100
}));
如果JS中访问window.ue发现为null,检查:
确保蓝图函数:
Android平台需要额外配置:
去年我们团队开发了一个虚拟展馆项目,需要实现以下功能:
通过改造WebBrowser插件,我们实现了:
性能测试结果显示,平均通信延迟仅3.2ms,完全满足实时交互需求。这套方案相比传统的WebSocket方案,不仅省去了服务器成本,还将通信延迟降低了85%。