UE HTML5开发二:双向通信调用V1.0
UE HTML5开发二:双向通信调用V1.0
- 前言
- cpp定义
- cpp实现
- web_get_data实现
- web_set_data
- web_set_data_string
- 导出函数给js调用
- 如何调用?
- js访问ue的数据:
- ue调用web_set_data_string设置数据
- js调用web_get_data获取数据
- ue访问js的数据:
- js中定义web_set_data_string设置数据
- UE该模块中web_get_data
- 下集预告:双向通信调用V2.0
前言
js导出c函数给js调用的流程为:HTML5JavaScriptFx.h中的函数继承C,然后HTML5JavaScriptFx.cpp或者HTML5JavaScriptFx.js中实现该函数,然后该函数在HTML5ToolChain.cs中的EXPORTED_FUNCTIONS中添加导出方法给js调用。
借鉴这个调用流程,1.0版本的通信逻辑为:将get数据和set数据两个方法导出给js,然后,UE和Web中的一方,web_set_data,然后另一方web_get_data检测数据修改,以达到传递数据的功能。
cpp定义
HTML5JavaScriptFx.h中定义web_get_data、web_set_data、web_set_data_string
// 确保在Emscripten环境下正确声明
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/html5.h>
#endif// 外部声明
extern unsigned char* WebDataBuffer;
extern int WebDataBufferSize;
extern "C" {
//以上原有函数声明不变 ...
#ifdef __EMSCRIPTEN__EMSCRIPTEN_KEEPALIVE
#endif char* web_get_data();#ifdef __EMSCRIPTEN__EMSCRIPTEN_KEEPALIVE
#endif void web_set_data(char* indata, int length);#ifdef __EMSCRIPTEN__EMSCRIPTEN_KEEPALIVE
#endif void web_set_data_string(char* jsonString);
}
cpp实现
//HTML5JavaScriptFx.cpp定义全局变量
unsigned char* WebDataBuffer = nullptr;
int WebDataBufferSize = 0;
web_get_data实现
char* web_get_data()
{return (char*)WebDataBuffer;
}
web_set_data
void web_set_data(char* indata, int length)
{// 释放旧内存if (WebDataBuffer){free(WebDataBuffer);WebDataBuffer = nullptr;}WebDataBufferSize = 0;// 分配新内存并拷贝数据(包括终止符)if (length > 0 && indata){WebDataBuffer = (unsigned char*)malloc(length + 1); // 多分配1字节给终止符if (WebDataBuffer){WebDataBufferSize = length;memcpy(WebDataBuffer, indata, length);WebDataBuffer[length] = '\0'; // 添加字符串终止符}}
}
web_set_data_string
void web_set_data_string(char* jsonString)
{if (jsonString){int length = strlen(jsonString);web_set_data(jsonString, length);}
}
导出函数给js调用
HTML5ToolChain.cs中的Result += " -s EXPORTED_FUNCTIONS数组中增加web_get_data、web_set_data、web_set_data_string,让js可以调用到该模块。
如何调用?
UE模块的.Build.cs引入HTML5JS
if (Target.Platform == UnrealTargetPlatform.HTML5){PrivateDependencyModuleNames.Add("HTML5JS");}
js访问ue的数据:
ue调用web_set_data_string设置数据
#ifdef __EMSCRIPTEN__
#include "HTML5JavaScriptFx.h"
#endif
UFUNCTION(BlueprintCallable, Category = "XXX")
void Pro_Web_Set_data(FString jsonString)
{#ifdef __EMSCRIPTEN__web_set_data_string(TCHAR_TO_ANSI(*jsonString));#endif
}
js调用web_get_data获取数据
var dataPtr = Module.ccall('web_get_data', 'number', [], []);
var resultString = UTF8ToString(dataPtr);
console.log(`web_get_data==${resultString}`);
ue访问js的数据:
js中定义web_set_data_string设置数据
function web_set_data_string(messageObj) {try {// 如果没有传入messageObj,则使用默认的对象if (!messageObj) {console.error('未传入messageObj');}var message = JSON.stringify(messageObj);console.warn('js发送消息:', message);// 检查Module是否已准备就绪if (window.Module && typeof window.Module.ccall === 'function') {// 直接传递字符串Module.ccall('web_set_data_string', null, ['string'], [message]);console.log('消息发送成功');} else {console.error('Module未准备就绪,无法发送消息');}} catch (error) {console.error('发送消息时出错:', error);}}
js调用:web_set_data_string(json对象);
UE该模块中web_get_data
#ifdef __EMSCRIPTEN__
#include "HTML5JavaScriptFx.h"
#endif
protected:virtual void Tick(float DeltaSeconds) override
{Super::Tick(DeltaSeconds);if (FrameTimer == FrameInterval){
#ifdef __EMSCRIPTEN__FString HTML5Msg = FString(UTF8_TO_TCHAR(web_get_data()));if (bMsgFramePrint){UE_LOG(LogTemp, Warning, TEXT("OnHTML5Msg:%s"), *HTML5Msg);} OnHTML5MsgCallback(HTML5Msg);
#endifFrameTimer = 0;}else{FrameTimer++;}
}public:UFUNCTION(BlueprintImplementableEvent, Category = "XXX")void OnHTML5MsgCallback(const FString& msg);UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "XXX")int32 FrameInterval = 5;UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "XXX")bool bMsgFramePrint = false;
private:int8 FrameTimer = 0;
蓝图中实现的OnHTML5MsgCallback事件会在一定帧间隔(FrameInterval变量决定)触发传递消息,这时候要在蓝图中做下消息处理,当消息产生变化时,判断消息是js设置,比如,json消息中有个字段是区别js还是ue来设置的数据。