cocos creator - WebView內部頁面的交互和層級問題

我們知道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, "*");
//如果因爲版本原因 _sgNode 被捨棄了,可以換成以下
this.webView._impl._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, "*");
            //如果因爲版本原因 _sgNode 被捨棄了,可以換成以下
			//this.webView._impl._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!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章