其实我一开始用的是webgl,比ios和Android的记录还晚。 由于没想到javascript 调用js,所以结合博客和自己的经历记录在这里。
Unity在WebGL平台上的特性及交互请参考官方文档
与Unity(WebGL)和JS沟通2022最新坐姿
1. 老方法
unity发布webplayer平台后,会输出html和unity3d文件。 我们的程序主要封装在unity3d文件中,html是网页的界面显示。 webPlayer 早已被弃用。 由于有些公司老项目可能还在使用这个平台,所以这里保留这部分解释。
1.Unity向JS发送消息
Unity想要和js交互,提供了一个函数:Application.ExternalCall(); 此功能仅限于网页播放器平台。 我们编辑发布的 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;
}
运行效果如下:
2、新版本
最近在使用webgl方面,2018.2.9版本弃用了Application.ExternalCall方法。 选择添加jslb文件作为中间层。我们搜索官方文档可以看到使用方法如下,官方文档WebGL: Interacting with browser scripting
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为unitywebgl平台打包后文件夹下index.html的gameInstance对象。
SendMessage的第一个方法是场景中对象的名称,第二个是附加到该对象的脚本上的方法名称,第三个参数是参数。 需要注意的是,虽然前两个是正确的,但是如果第三个参数没有正确传递的话javascript 调用js,就会报错说找不到该方法
下面是上面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文件的时候会写一个名字,两方名字不同就会出现问题。具体可以参考UnityWebGL错误集合
因为这里使用的是2021.3.8f1c1,所以之前的unity包的索引比较大,原来的gameInstance早就丢失了。 还可以在index.html的onLoad方法中添加反弹语句。 onLoad 方法在生成的项目的index.html 上可用。 这里的unityInstance是bounce函数传入的。
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);
});
};
测试后就OK了。
需要注意的一点是,即使此时可以传输信息,当唤醒过去时,大部分脚本也可能不会被执行。 所以这个时候就需要存储变量。 有些变量直到唤醒后才会使用。
可以在unity编辑器的Aseet文件夹下的WebGLTemplates上定义index.html来自定义WebGL加载屏幕
具体流程可以百度WebGLTemplates。
或者这里有更好的参考【Unity3D日常开发】Unity3D模板WEBGL模板自定义模板教程
还有一点需要注意的是,当onLoad刚刚结束时,Unity的生命周期可能还没有开始。
这时候向Unity发送消息完全是靠运气,有时能收到,有时收不到。
所以做法就是延迟一段时间,然后给它发消息。
里面
unityInstance.SendMessage('Main Camera', 'ReceieveFromJS', "456");
变成
setTimeout(function(){
// 延迟调用的方法
unityInstance.SendMessage('ReceiveFromJSToken',
'ReceiveFromJSMethod1', window.location.href);
}, 0.7);
打包的时候报错,jslib上不能有英文。 评论也不予受理。 否则会报这个错误。
Building LibraryBeeartifactsWebGLbuilddebug_WebGL_wasmbuild.js failed with output:
Traceback (most recent call last):
File "C:Program FilesUnityHubEditor2021.3.8f1c1EditorDataPlaybackEnginesWebGLSupportBuildToolsEmscriptenemscriptenemcc2.py", line 3571, in <module>
sys.exit(main(sys.argv))
File "C:Program FilesUnityHubEditor2021.3.8f1c1EditorDataPlaybackEnginesWebGLSupportBuildToolsEmscriptenemscriptenemcc2.py", line 3564, in main
ret = run(args)
File "C:Program FilesUnityHubEditor2021.3.8f1c1EditorDataPlaybackEnginesWebGLSupportBuildToolsEmscriptenemscriptenemcc2.py", line 1082, in run
phase_post_link(options, wasm_target, wasm_target, target)
File "D:objwindows-release37amd64_Releasemsi_pythonzip_amd64contextlib.py", line 74, in inner
File "C:Program FilesUnityHubEditor2021.3.8f1c1EditorDataPlaybackEnginesWebGLSupportBuildToolsEmscriptenemscriptenemcc2.py", line 2400, in phase_post_link
phase_emscript(options, in_wasm, wasm_target, memfile)
File "D:objwindows-release37amd64_Releasemsi_pythonzip_amd64contextlib.py", line 74, in inner
File "C:Program FilesUnityHubEditor2021.3.8f1c1EditorDataPlaybackEnginesWebGLSupportBuildToolsEmscriptenemscriptenemcc2.py", line 2428, in phase_emscript
emscripten.run(in_wasm, wasm_target, final_js, memfile)
File "C:Program FilesUnityHubEditor2021.3.8f1c1EditorDataPlaybackEnginesWebGLSupportBuildToolsEmscriptenemscriptenemscripten.py", line 830, in run
emscript(in_wasm, out_wasm, outfile_js, memfile, shared.DEBUG)
File "C:Program FilesUnityHubEditor2021.3.8f1c1EditorDataPlaybackEnginesWebGLSupportBuildToolsEmscriptenemscriptenemscripten.py", line 308, in emscript
glue, forwarded_data = compile_settings()
File "C:Program FilesUnityHubEditor2021.3.8f1c1EditorDataPlaybackEnginesWebGLSupportBuildToolsEmscriptenemscriptenemscripten.py", line 178, in compile_settings
cwd=path_from_root('src'), env=env)
File "C:Program FilesUnityHubEditor2021.3.8f1c1EditorDataPlaybackEnginesWebGLSupportBuildToolsEmscriptenemscriptentoolsshared.py", line 216, in run_js_tool
return check_call(command, *args, **kw).stdout
File "C:Program FilesUnityHubEditor2021.3.8f1c1EditorDataPlaybackEnginesWebGLSupportBuildToolsEmscriptenemscriptentoolsshared.py", line 202, in check_call
return run_process(cmd, *args, **kw)
File "C:Program FilesUnityHubEditor2021.3.8f1c1EditorDataPlaybackEnginesWebGLSupportBuildToolsEmscriptenemscriptentoolsshared.py", line 97, in run_process
ret = subprocess.run(cmd, check=check, input=input, *args, **kw)
File "D:objwindows-release37amd64_Releasemsi_pythonzip_amd64subprocess.py", line 474, in run
File "D:objwindows-release37amd64_Releasemsi_pythonzip_amd64subprocess.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&)
工程实例
UnityWebGL后端js交互示例项目