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