Unity3D开发之WebGL平台上 unity和js前端通信交互
一.老版方法unity发布webplayer平台后会输出html和unity3d文件。我们的程序主要被打包在unity3d文件里,而html则是网页的界面显示。1.Unity发送消息给JSunity想要和js交互,提供了一个函数:Application**.ExternalCall()**;此函数仅限于webplayer平台下。我们编辑发布的html文件,在里面加入我们的js脚本如下:fu...
自己虽然最开始弄的就是webgl但是一直比ios和安卓记录的都要晚,因为一直没想到,所以这里结合某个博客加上自己的经历记录一下
关于Unity在WebGL平台的特性和交互 可以参考官方文档
以及 Unity(WebGL)与JS通讯2022最新姿势
一.老版方法
unity发布webplayer平台后会输出html和unity3d文件。我们的程序主要被打包在unity3d文件里,而html则是网页的界面显示,webPlayer已经被弃用了,鉴于一些公司可能旧项目依然使用这个平台,这里就保留这部分解释。
1.Unity发送消息给JS
unity想要和js交互,提供了一个函数:Application.ExternalCall();此函数仅限于webplayer平台下。我们编辑发布的html文件,在里面加入我们的js脚本如下:
function GetID(id)
{
alert("传入id:"+id);
}
在unity里我们在start函数里调用
Application.ExternalCall("GetID","吴彦祖");
使用浏览器打开html文件,就会出现如下弹窗:
2.JS发送消息给unity
我们在刚才的js函数里添加一句代码:
function GetID(id)
{
alert("传入id:"+id);
//发送消息给unity 第一个参数:挂在脚本的物体 第二个参数:unity被调用的函数 第三个参数:函数传入的参数
u.getUnity().SendMessage("Main Camera","GetIDInfo","JayW")
}
在unity里创建一个函数用来接收处理:
public void GetIDInfo(string id)
{
text.text = id;
}
运行效果如下:
二.新版方法
最近在使用webgl方面,2018.2.9版本弃用了Application.ExternalCall方法。选择添加一个jslb文件作为中间层。我们搜官方文档可以看到使用方式如下,官方文档 WebGL:与浏览器脚本交互
Unity主动发起调用js函数
首先创建一个文本,文件格式保持为.jslib。这个文件存放的是c#主动通信前端的中间方法,我们在里面增加我们要接受c#传来的数据和js要调用的函数。 代码如下:
mergeInto(LibraryManager.library, {
//这里是代码1
JSLog: function (str) {
var strs=Pointer_stringify(str);
//这个Log方法是前端那边写的方法
Log(strs);
},
//这里可以添加若干个方法,方法之间记得用逗号隔开,
//否则WebGL平台打包的时候会报错
});
注意:这里一定要用unity内置函数Pointer_stringify将传进来的str转换成字符串。如果不转换str存储的是内存地址位。传到js就是一堆数字。最后保存文件,将文件放到unity工程下的Plugins文件夹内。
然后在c#代码块里,我们加上我们要调用的方法:
[DllImport("__Internal")]
private static extern void JSLog(string str);//此处传入的类型和调用时候传入的数据类型一定要一致
void Start()
{
//如果有返回值,可以定义变量接收返回值
JSLog("666");
}
这里我们在C#里面调用了工程中的jslib文件的函数。
最后使我们打包出来的html文件里,在scrip块内加入jslib的JSLog里面被调用的函数Log:
function Log(str)
{
console.log(str);;
gameInstance.SendMessage('Main Camera','GetStr',String(str));
}
在jslib的方法里面,如果调用前端的方法后有字符串返回 则需要这样写,字符串才能返回到c#里面
//获取服务器访问的认证
getServerAuth: function(){
var token = window.THREE_TOKEN();
console.log("jslib getServerAuth token " + token);
//这样写
var bufferSize = lengthBytesUTF8(token) + 1;
var buffer = _malloc(bufferSize);
stringToUTF8(token, buffer, bufferSize);
return buffer;
},
js主动发起Unity函数调用
前端调用的时候是这样的
this.gameInstance.SendMessage('OutSideInteractor', 'ReceiveDlteAddedProduct ', id)
其中 this.gameInstance是unity webgl平台出包后的文件夹里面的index.html的gameInstance对象.
SendMessage方法第一个是场景里面的物体名字,第二个是物体所挂脚本里面的某个方法名字,第三个参数是参数,要注意的是,即使前两个写对了,如果第三个参数没传对,也会报错说找不到方法
下面是index.html里面定义的内容,前端调用Unity的代码也可以写到这里,但更多是写到前端自己的某个脚本里面
var gameInstance = UnityLoader.instantiate("gameContainer", "Build/CPWEBGL.json", { onProgress: UnityProgress })
window.ReceiveAddSceneItemStr = function (e) {
gameInstance.SendMessage('OutSideInteractor', 'ReceiveAddSceneItemStr', e)
}
这里的CPWEBGL是我打webgl包的最后一个文件夹的名字,生成的json和unityLoad文件的文件名字与这个名字相同,unityLoad文件是Unity的主要内容的存放文件,这个名字一般要和前端约定好,因为前端加载Unity文件的时候会写死一个名字,双方的名字不同的时候会出现问题。具体参考 Unity WebGL错误集锦
因为这里使用的2021.3.8f1c1,后面的unity打包的index出入比较大,原来的gameInstance已经找不到了。 也可以在index.html的onLoad方法里面加上回调的语句,onLoad这个方法在生成好的工程的index.html里面是有的。这里的unityInstance由回调函数传入。
script.onload = () => {
createUnityInstance(canvas, config, (progress) => {
progressBarFull.style.width = 100 * progress + "%";
}).then((unityInstance) => {
loadingBar.style.display = "none";
fullscreenButton.onclick = () => {
unityInstance.SetFullscreen(1);
};
unityInstance.SendMessage('Main Camera', 'ReceieveFromJS', "456");
}).catch((message) => {
alert(message);
});
};
经过测试是可以的。
要注意的一点是这时虽然能够传输信息,但是传输过去的时候对于大多数的脚本,其可能awake都还没有执行。所以这时进行变量的存储的比较必要的。有些变量在awake之后才进行使用。
index.html可以在unity的编辑器的Aseet文件夹下面的WebGLTemplates里面定义好,用于自定义WebGL加载画面
具体过程可以百度WebGLTemplates.
或者这里有一篇比较好的参考 【Unity3D日常开发】Unity3D模板 WEBGL模板 自定义Templates 使用教程
另外还要注意的一个点是,在onLoad刚刚结束的时候,可能Unity的生命周期还没开始。
此时往Unity里面发送消息完全是靠 运气的,有时能接收到,有时不能接收到。
所以做法是延迟一段时间,再往里面发送消息。
上面的
unityInstance.SendMessage('Main Camera', 'ReceieveFromJS', "456");
改成
setTimeout(function(){
// 延迟调用的方法
unityInstance.SendMessage('ReceiveFromJSToken',
'ReceiveFromJSMethod1', window.location.href);
}, 0.7);
报错
- 在打包的时候,jslib里面不能够有中文。注释也是不行的。否则就会报这个错。
Building Library\Bee\artifacts\WebGL\build\debug_WebGL_wasm\build.js failed with output:
Traceback (most recent call last):
File "C:\Program Files\Unity\Hub\Editor\2021.3.8f1c1\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten\emscripten\emcc2.py", line 3571, in <module>
sys.exit(main(sys.argv))
File "C:\Program Files\Unity\Hub\Editor\2021.3.8f1c1\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten\emscripten\emcc2.py", line 3564, in main
ret = run(args)
File "C:\Program Files\Unity\Hub\Editor\2021.3.8f1c1\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten\emscripten\emcc2.py", line 1082, in run
phase_post_link(options, wasm_target, wasm_target, target)
File "D:\obj\windows-release\37amd64_Release\msi_python\zip_amd64\contextlib.py", line 74, in inner
File "C:\Program Files\Unity\Hub\Editor\2021.3.8f1c1\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten\emscripten\emcc2.py", line 2400, in phase_post_link
phase_emscript(options, in_wasm, wasm_target, memfile)
File "D:\obj\windows-release\37amd64_Release\msi_python\zip_amd64\contextlib.py", line 74, in inner
File "C:\Program Files\Unity\Hub\Editor\2021.3.8f1c1\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten\emscripten\emcc2.py", line 2428, in phase_emscript
emscripten.run(in_wasm, wasm_target, final_js, memfile)
File "C:\Program Files\Unity\Hub\Editor\2021.3.8f1c1\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten\emscripten\emscripten.py", line 830, in run
emscript(in_wasm, out_wasm, outfile_js, memfile, shared.DEBUG)
File "C:\Program Files\Unity\Hub\Editor\2021.3.8f1c1\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten\emscripten\emscripten.py", line 308, in emscript
glue, forwarded_data = compile_settings()
File "C:\Program Files\Unity\Hub\Editor\2021.3.8f1c1\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten\emscripten\emscripten.py", line 178, in compile_settings
cwd=path_from_root('src'), env=env)
File "C:\Program Files\Unity\Hub\Editor\2021.3.8f1c1\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten\emscripten\tools\shared.py", line 216, in run_js_tool
return check_call(command, *args, **kw).stdout
File "C:\Program Files\Unity\Hub\Editor\2021.3.8f1c1\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten\emscripten\tools\shared.py", line 202, in check_call
return run_process(cmd, *args, **kw)
File "C:\Program Files\Unity\Hub\Editor\2021.3.8f1c1\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\Emscripten\emscripten\tools\shared.py", line 97, in run_process
ret = subprocess.run(cmd, check=check, input=input, *args, **kw)
File "D:\obj\windows-release\37amd64_Release\msi_python\zip_amd64\subprocess.py", line 474, in run
File "D:\obj\windows-release\37amd64_Release\msi_python\zip_amd64\subprocess.py", line 926, in communicate
UnicodeDecodeError: 'gbk' codec can't decode byte 0x99 in position 393654: illegal multibyte sequence
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
工程示例
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)