我們知道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>