T O P

[资源分享]     cocos creator - WebView内部页面的交互和层级问题

  • By - 楼主

  • 2019-11-21 12:24:14
  • 我们知道creator里的WebView,VideoPlayer等特殊组件有一个非常严重的问题,就是不管你怎么设置层级,这类组件始终处于最上层!其他UI组件会被遮挡。

    我们打开浏览器运行,F12检测元素就可以清楚的看到他们的层级关系。
    如下图:

    在这里插入图片描述

    通过上图我们可以清楚的看到,video(videoPlayer组件) 和 iframe(webView组件) 在 canvas(GameCanvas) 上层,而我们creator内置UI组件都是在GameCanvas层渲染的,所以不管我们怎么改UI层级都无效。

    解决方案可以参考我之前的一篇文章: videoPlayer组件一直处于在最上层的问题

    其实除了上述的办法,还有一个解决方案,就是我们可以通过自己写一个简单的html页面来中转!

    大致思路:

    首先我们自己用nginx搭建一个简单的html页面,在通过webView组件加载我们自己的web页面,然后在我们自己的页面加载一些需要的video或者其他网页,一些需要显示在Video组件上层的组件我们就可以通过html标签来实现了(需要一点web知识),然后和creator JS交互就可以了。

    如何与 WebView 内部页面进行交互呢?:

    可以参考一下
    官方文档

    个人感觉官方文档讲得不够全面。

    我的实现如下:

    首先我们先来看下官方的:
    在这里插入图片描述
    我们可以看到,Web平台上会出现跨域的问题,所以我们需要分别对web平台和移动平台做处理,

    web平台:

    在Web上我们可以通过window.postMessage 实现跨域消息传递:

    cocos 发送消息到 web:

    cocos JS:

    this.webView._sgNode._renderCmd._iframe.contentWindow.postMessage(data, "*");
    

    这里需要注意的是:我们必须等webView加载完成之后才能发送。

    html JS

    //接收来自cocos的消息
      window.addEventListener('message', function (e) {
            var data = e.data;//参数
            console.log("-----------message--------------", data)
      });
    

    web 发送消息到 cocos:

    html JS

    //browser 浏览器下,向cocos发送消息
    parent.postMessage("------------hello!-----cocos---------", "*")
    

    cocos JS:

    if (cc.sys.isBrowser) {
        //这里是浏览器环境下, 接收web传过来的消息
        window.addEventListener('message', function (e) {
            console.log("----cocos---",e.data);
        })
    }
    

    演示如下:
    在这里插入图片描述
    以上是运行在浏览器环境下的交互


    移动平台:

    移动平台下就和官网的区别不大了。

    首先需要初始化:

    //初始化
     init() {
            // 这里是与内部页面约定的关键字,请不要使用大写字符,会导致 location 无法正确识别。
            var scheme = "testkey";
            //这里是移动端, 接收web传过来的消息
            function jsCallback(target, url) {
                // 这里的返回值是内部页面的 URL 数值,需要自行解析自己需要的数据。
                var str = url.replace(scheme + '://', ''); // str === 'a=1&b=2'
                // webview target
                console.log("jsCallback-------str-------", str);
                window.closeWebView(target, url);
            }
            this.webView.setJavascriptInterfaceScheme(scheme);
            this.webView.setOnJSCallback(jsCallback);
    
            //web
            window.closeWebView = this.closeWebView.bind(this);
    },
    

    cocos 发送消息到 web:

    cocos JS:

    let data = {
    	id:123456
    }
    data = JSON.stringify(data); //注意这里需要把参数序列化
    //调用web页面 定义的全局函数
    this.webView.evaluateJS("setBackgroundColor(" + data + ")");
    

    web 发送消息到 cocos :

    html JS

     function onClick() {
      	 console.log("-------web--------onClick----->>cocos JS-------------", window.isNative)
         //android or ios
         document.location = 'testkey://a=1&b=2'
     }
    

    demo完整代码:

    cocos JS:

    if (cc.sys.isBrowser) {
        //这里是浏览器环境下, 接收web传过来的消息
        window.addEventListener('message', function (e) {
            console.log("----cocos---",e.data);
            window.closeWebView(e);
        })
    }
    
    cc.Class({
        extends: cc.Component,
    
        properties: {
            webView: cc.WebView,
            debugText: cc.Label
        },
    
        start() {
            this.setDebugText("start.....")
            this.webView.url = "web ip 地址"; // 如: "http://127.0.0.1:8190/web/"
            this.init();
        },
    
        init() {
            // 这里是与内部页面约定的关键字,请不要使用大写字符,会导致 location 无法正确识别。
            var scheme = "testkey";
            //这里是移动端, 接收web传过来的消息
            function jsCallback(target, url) {
                // 这里的返回值是内部页面的 URL 数值,需要自行解析自己需要的数据。
                var str = url.replace(scheme + '://', ''); // str === 'a=1&b=2'
                // webview target
                console.log("jsCallback-------str-------", str);
                window.closeWebView(target, url);
            }
            this.webView.setJavascriptInterfaceScheme(scheme);
            this.webView.setOnJSCallback(jsCallback);
    
            //web
            window.closeWebView = this.closeWebView.bind(this);
        },
    
        setDebugText(str) {
            this.debugText.string = str
        },
    
        //绑定按钮
        cocosToWeb() {  
            let data = {
                width: this.webView.node.width,
                height: this.webView.node.height,
                isNative: cc.sys.isNative,
                color:"#FF9800"
            }
            let text;
            console.log("------cocos------data-----------", data)
            //浏览器
            if (cc.sys.isBrowser) {
                console.log("-----cocos------Browser---------");
                text = "-----cocos------Browser---------";
                this.webView._sgNode._renderCmd._iframe.contentWindow.postMessage(data, "*");
            } 
            //移动端
            else if (cc.sys.isNative) 
            { 
                console.log("-----cocos------Native---------");
                text = "-----cocos------Native---------";
                data = JSON.stringify(data);
                //setBackgroundColor 是 web 全局函数, data 参数
                this.webView.evaluateJS("setBackgroundColor(" + data + ")");
            }
    
            this.webView.node.active = true;
            this.setDebugText(text)
        },
    
        //关闭WebView
        closeWebView(e, url) {
            this.webView.node.active = false;
            this.setDebugText("--------cocos-----close----webView-------" + url);
        },
    
        //事件
        onWebFinishLoad: function (sender, event) {
            if (event === cc.WebView.EventType.LOADED) {
                this.setDebugText("----webView---loaded---finish!!----")
                this.cocosToWeb()
            } else if (event === cc.WebView.EventType.LOADING) {
                this.setDebugText("----webView---loading----")
            } else if (event === cc.WebView.EventType.ERROR) {
                this.setDebugText("----webView---load---error----")
            }
        },
    
    });
    
    

    Html:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>cocos web</title>
        <style>
            body {
                margin: 0;
                padding: 0;
                background: rgb(94, 94, 94);
            }
            div {
                width: 100%;
                height: 50px;
                position: absolute;
                margin: auto;
                left: 0;
                right: 0;
                bottom: 0;
                text-align: center;
                font-size: 30px;
            }
    
            iframe{
                width: 50%;
                height: 80%;
                position: absolute;
                margin: auto;
                left: 0;
                right: 0;
                top: 0;
                text-align: center;
                font-size: 30px;
            }
    
            button {
                position: absolute;
                width: 200px;
                height: 30px;
                background: red;
                top: 2px;
                right: 20%;
                border: 0;
            }
        </style>
    </head>
    
    <body>
        <iframe id="iframeID" src="http://www.baidu.com" frameborder="0"></iframe>
        <div id="text"></div>
        <button type="button" onclick="onClick()">触发cocos 关闭webView</button>
    </body>
    <script>
        let iframeWeb = document.getElementById("iframeID");
    
        // ---------------browser-------need--------
        window.addEventListener('message', function (e) {
            var data = e.data;  //e.data 里面有自己所传的所有参数 可以根据参数做自己的判断
            console.log("--------------this is web message--------------", data)
            setBackgroundColor(data);
        });
        // ---------------browser---------------
        function setBackgroundColor(data) {
            console.log("-------web--------data-------" + data)
            window.isNative = data.isNative;
            document.getElementsByTagName("body")[0].style.background = data.color;
            document.getElementById("text").innerHTML = "this is cocos send msg color :" + data.color;
            document.getElementById("iframeID").innerHTML = "this is cocos send msg color :" + data.color;
            // setIframeSize(data)
        }
    
        function setIframeSize(data){
            if (data.isNative) { //----------mobile---------
                let cocosIframe = window.parent.document.documentElement;
                console.log("-----mobile--web-------size------" + cocosIframe.clientWidth + "---" + cocosIframe.clientHeight);
                iframeWeb.style.width = cocosIframe.clientWidth + "px";
                iframeWeb.style.height = cocosIframe.clientHeight + "px";
            }else{//----------browser---------
                console.log("----browser---web-------size------" + data.width + "---" + data.height);
                iframeWeb.style.width = data.width + "px";
                iframeWeb.style.height = data.height + "px";
            }
        }
    
        function onClick(param) {
            console.log("-------web--------onClick----->>cocos JS-------------", window.isNative)
            if (window.isNative) {
                //android or ios
                document.location = 'testkey://a=1&b=2'
            } else {
                //browser 浏览器下,向cocos发送消息
                parent.postMessage("------------hello!-----cocos---------", "*")
            }
        }
    </script>
    
    </html>
    

    end!

    本帖子中包含资源

    您需要 登录 才可以下载,没有帐号?立即注册