WebGL 内嵌网页的一种解决方案

  之前使用的 ZFBrowser 嵌入方案可以发布到 Win, OS, Linux 上, 可是其它的就不行, 因为它用的谷歌内核嘛, 在 WebGL 上照理来说应该是最方便的啊, 因为它本身就是运行在浏览器内核上的, 前面的 BrowserInput 已经研究过向网页注入代码以及调用了, 现在试试在 WebGL 环境下来注入代码, 来创建简单的内嵌网页看看.

  Unity2017之前的方法跟 ZFBrowser 的很像, 用起来很方便, 可是以后会被禁用 :

[Obsolete("Application.ExternalEval is deprecated. See https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html for alternatives.")]
public static void ExternalEval(string script);

[Obsolete("Application.ExternalCall is deprecated. See https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html for alternatives.")]
public static void ExternalCall(string functionName, params object[] args);

  也不知道他们咋想的, 官方给的新方法是写一个 XXX.jslib 文件, 里面写的代码就是注入形式的代码, 通过 [DllImport("__Internal")] 的方式引用方法, 感觉就是编译成C++代码了, 先不说它效率高不高, 单是一个使用上就很蛋疼了啊, 看看一个 .jslib 文件, 官方的 :

mergeInto(LibraryManager.library, {

  HelloString: function (str) {
    window.alert(Pointer_stringify(str));    // unity传过来的string, 需要进行转换才能作为浏览器字符串
  },

  PrintFloatArray: function (array, size) {  // 数组还要自己传递长度
    for(var i = 0; i < size; i++)
    console.log(HEAPF32[(array >> 2) + i]);    // float[] 数组, 这样转换够奇葩了
  },

  StringReturnValueFunction: function () {
    var returnStr = "bla";                    // 网页字符串
    var bufferSize = lengthBytesUTF8(returnStr) + 1;
    var buffer = _malloc(bufferSize);
    stringToUTF8(returnStr, buffer, bufferSize);
    return buffer;                            // 传递给Unity的字符串经过转换才能传递...
  },
  
});

Unity 调用 :

    [DllImport("__Internal")]
    private static extern void HelloString(string str);

    [DllImport("__Internal")]
    private static extern void PrintFloatArray(float[] array, int size);
    
    [DllImport("__Internal")]
    private static extern string StringReturnValueFunction();
    
    void Start()
    {
        HelloString("This is a string.");            // 传递string给WebGL

        float[] myArray = new float[10];
        PrintFloatArray(myArray, myArray.Length);    // 传递Array给WebGL, 长度也要传...

        Debug.Log(StringReturnValueFunction());      // 从WebGL获取字符串
    }    

  这样反人类的做法, 估计是不能成事的了, Unity走了一条歪路......

  PS : 既然注入 JavaScript 这么绕, 那肯定是为了性能了, 看了一下编译方案, 频繁出现 Emscripten 这个字眼, 查了一下, 就是这个编译器, 在编辑器文件夹下也找到了

WebGL 内嵌网页的一种解决方案_第1张图片

 

  不管怎样顺着来吧, 就是注入一个创建 iframe 的代码, 让它能够显示在 Unity 的窗口范围之内, 如果成功的话, 加上自动跟随和缩放功能, 它就是半个嵌入式网页了, 因为它只能实现最上层显示, 不能像 ZFBrowser 那样嵌入 UI 或是任意 Mesh 上显示, 没有真正的遮挡.

   添加一个创建 iframe 的代码 :

mergeInto(LibraryManager.library, {

    CreateIFrame: function () 
    {
        window.alert("CreateIFrame!!!");
        var div = window.document.createElement('div');    
        div.style.zIndex = "100";
        div.style.position="absolute";
        window.document.body.appendChild(div);

        var iframe = window.document.createElement('iframe');        
        iframe.style.zIndex = "1000";
        iframe.style.position="absolute";
        iframe.src = "http://XXXX/OOOO/";
        div.appendChild(iframe);
    },
  
});

  Unity 添加调用代码 :

    [DllImport("__Internal")]
    private static extern void CreateIFrame();
    
    void Start()
    {
        CreateIFrame();
    }    

 

  PS : Unity使用的是绝对位置, 反而比较方便进行坐标对齐操作.

  运行之后大概是这个样子, 正常实现了网页覆盖, 因为原本就是嵌入到Unity的网页, 网页背景是透明的 : 

WebGL 内嵌网页的一种解决方案_第2张图片

 

  要做成嵌入式的感觉, 只需要根据Unity的坐标计算换算到网页, 设置 iframe 位置 / 缩放 就可以了, 没什么好说的, 不过因为没有遮挡关系, 没有什么实用价值...

 

你可能感兴趣的:(WebGL 内嵌网页的一种解决方案)