Bootstrap

Unity WebGl和前端(Angular)相互调用(含跨域问题)

在Unity官方文档中就已经介绍了Unity和JS相互调用的问题,但是我们实际的应用中往往是使用iframe来展示WebGL。这样不但是webgl和js相互调用的问题,还包含了iframe跨域的问题。

我们的项目中前端使用的是angular框架,就以angular为基础来说一下这个问题,当然vue的前端框架应该都一样的原理。

首先说一下unity和js相互调用的问题

Unity和JS的相互调用

unity调用js:

1.首先在Unity/Assets/Plugins目录下存放你需要调用的js。

2.在Plugins目录下新建文本文档__Internal,后缀改为jslib。

 3.编写脚本内容。

mergeInto(LibraryManager.library, {
  //开启新窗口
  OpenUrlWindow:function(str,counts) 
  {
      OpenUrl_Window(Pointer_stringify(str),Pointer_stringify(counts)); //调用js方法
  },
  //关闭新窗口
  CloseUrlWindow:function()
  {
      CloseUrl_Window();//调用js方法
  },

  FullScreen:function(){
    
  },
    JumpUrl:function(str) 
  {
      Jump_Url(Pointer_stringify(str)); //调用js方法
  }
});

我们以JumpUel为例,我们要在C#中引入动态链接库,  [DllImport("__Internal")],然后C#中调用JumpUrl函数即可。

4.C#调用。这里我们点击场景中的一个物体就触发这个函数。以上是在unity中的处理。

 string str ="unity调用JS";

    [DllImport("__Internal")]
    private static extern void JumpUrl(string str);
    void Start()
    {
        
    }
    private void OnMouseDown()
    {
        JumpUrl(str);
    }

5.打包成webgl。

6.打包成功后使用VSCode打开index文件,是一个html文件代码。我们在script语句块中编写相应的方法,注意:我们在unity中JumpUrl对应的js方法是Jump_Url不要吧函数名字写错。

  function Jump_Url(str){
        console.log(str);
      
      }
    

编写完成后我们打开运行,点击场景中的物体,就会调用js中的方法。

JS调用Unity

js调用unity就相对简单多了。

1.在unity场景中创建一个物体,挂载上要掉用的脚本。

 2.在脚本中随便写个方法。  public void Close(){Debug.log("我是Unity");}

3.打包,因为unity的版本不同打出来的包的index内容也不同,只要找到unityInstance,在他下边调用即可。

unityInstance.SendMessage('场景中挂载脚本的物体名','方法名')
unityInstance.SendMessage('场景中挂载脚本的物体名','方法名','方法对应参数')

 以上完成了js调用unity的的方法。知道以上的方法以后,并不能真正的解决我们开发中遇到的问题,因为我们往往要使用iframe将webgl嵌入到我们的前端页面,我们需要跨域来相互调用。

iframe跨域调用

iframe跨域调用涉及到父子之间的调用,webgl是子,嵌入到的页面就是父。

父调子(JS调用Unity)

1.父的代码

  <!-- html:iframe嵌入 -->
 <iframe allowfullscreen="true" id="unity3d" style="width: 100%;height: 100%;padding:2px 2px 0 2px" frameborder="0" scrolling="no"
                  [src]="Workshop3dAddress | safe">
   </iframe>


//js代码
 change3D(){
    let ifim:any;
    ifim =window.document.getElementById('unity3d');

    ifim.contentWindow.postMessage("ref",'*')
  }

ref会传入到子中,我们可以使用不同的值来区分调用的方法。

2.子的代码

   script.onload = () => {

        var unitysf;
        createUnityInstance(canvas, config, (progress) => {
          progressBarFull.style.width = 100 * progress + "%";
        }).then((unityInstance) => {
          loadingBar.style.display = "none";
          unitysf=unityInstance

        }).catch((message) => {
          alert(message);
        });

        addEventListener("message",e=>{
          console.log("父调用子")
          unitysf.SendMessage("JSToUnity","CameraMove");
          })
        
      };

addEventListener就是我们监听前端调用的方法。 unitysf=unityInstance不用过多解释。在监听的方法中,我们写入js调用unity的方法,就完成了前端跨域调用unity的方法。e就是父中传过来的参数,根据e的不同我们可以判断调用那个函数。

子调父(Unity调用JS)

1.子的代码


var data ="unity"
data=JSON.parse(JSON.stringify(data));
      function Jump_Url(str){
      
        console.log(str);
       window.parent.postMessage({
   data: JSON.stringify(data)
},'*')
      }

这里我们要有两个注意的地方,1是要将data转化一边data=JSON.parse(JSON.stringify(data));

2是  window.parent.postMessage({ data: JSON.stringify(data)},'*')记得在后边加一个*解决跨域的问题。

2.父的代码

  var self = this;
    window.addEventListener('message', function(event) {
      console.log('Received message from iframe:', event.data);

      self.navi(self.groups[0]);//js代码
      self.updateView();//js代码
    }, false);

这里注意:因为addEventListener后是一个函数说以要加一个 var self = this;才能调用JS中的方法,(前端的基础知识)。

以上我们完成了Unity跨域调用JS的方法。

;