项目开发进程中,业务提出新需求,需要接入视频直播。为此,开始接触火山引擎视频直播。火山引擎方值负责提供观播SDK,综合考虑现有技术栈,采用集成Web SDK方式,接入观播功能。直播通过企业版腾讯会议方式进行推流操作。
前端采用uni-app Webview嵌套H5页面方式,重点处理逻辑集中在H5观播页面中,因为涉及观播activityId值的获取,故需要实现Webview与H5页面双向通信机制。
uni-app在 App 平台同时支持网络网页和本地网页,但本地网页及相关资源(js、css等文件)必须放在 uni-app 项目根目录->hybrid->html
文件夹下或者 static
目录下,因为这个目录下的文件不会被编译。
注意⚠️:每个vue
页面,其实都是一个webview
,而vue
页面里的web-view
组件,其实是webview
里的一个子webview
。这个子webview
被append
到父webview
上。
var currentWebview = this.$scope.$getAppWebview(); //此对象相当于html5plus里的plus.webview.currentWebview()。在uni-app里vue页面直接使用plus.webview.currentWebview()无效
currentWebview.append(wv);//一定要append到当前的页面里!!!才能跟随当前页面一起做动画,一起关闭
vue
页面内容如下:
<template>
<view>
<web-view :src="url">web-view>
<view>
template>
<script>
export default {
data() {
return {
url: ''
}
},
onLoad() {
// 默认一个你的html(h5地址)
this.url = '/hybrid/html/vedioLive.html'
},
mounted(){
// 需要监听 message 之后触发方法
window.addEventListener("message", this.handlePostMessage);
},
methods: {
// 触发方法
handlePostMessage(data) {
console.log(data)
console.log(data.data.data.arg.data)
if (data.data.data.arg.data == 'h5页面传的值') {
// 给url重新赋值
this.url = ""
} else if (data.data.data.arg.data == '判断返回uniapp页面') {
// 其他的跳转查看uniapp官网
uni.switchTab({
url: '/pages/xxx/index'
});
}
},
}
}
script>
html页面内容如下:
DOCTYPE html>
<html style="height: 100%">
<head>
<title>企业直播WEB SDK DEMOtitle>
<link rel="shortcut icon"
href=//p1-live.byteimg.com/tos-cn-i-gjr78lqtd0/3f061494968a653d3409e0607259939e.png~tplv-gjr78lqtd0-image.image
sizes="16x16">
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,
maximum-scale=1.0, user-scalable=no, shrink-to-fit=no, viewport-fit=cover">
<link rel="stylesheet"
href="https://lf-cdn-tos.bytescm.com/obj/static/livesaas-client/mobile/css/index.1.1.0.css">
<style>
.app {
display: flex;
height: 100%;
flex-direction: column;
background-image: url('//p6-live.byteimg.com/tos-cn-i-gjr78lqtd0/923a9e572712a19d5b8c84fa66e90bd6.png~tplv-gjr78lqtd0-image.image');
background-size: 100% 100%;
background-attachment: fixed;
}
.player {
width: 100vw;
height: calc(100vw / 16 * 9);
}
.menu {
flex: 1 1;
min-height: 300px;
overflow: hidden;
}
style>
head>
<body style='
font-size: 10px; margin: 0; background-color: #080B12;
height: 100%; overflow: hidden;'>
<div class="app">
<div id="player" class="player">div>
<div id="content" class="menu">div>
div>
<script src="https://lf-cdn-tos.bytescm.com/obj/static/livesaas-client/mobile/js/index.1.1.0.js">script>
body>
<script>
var webSDK = new window.ByteLiveWebSDK({
activityId: 1740896046764078,
token: 'psNBho',
service: 'liveDemo',
mode: 1,
modules: [
{
id: "player", // 页面元素 ID, 播放器模块会嵌入到此元素内
mode: "player",
},
{
id: "content", // 页面元素 ID, 菜单模块会嵌入到此元素内
mode: "menu"
}
],
options: {
mobileBackgroundTransparent: true,
saveUserInfo: true,
}
})
webSDK.on('error', console.log);
script>
html>
有关参数、回调函数等详细用法,详参接口文档。
uni-app
的vue
页面本身是一个webview
,vue
页面里的web-view
组件,其实是一个子webview
。但一个vue
页面不能放多个web-view
组件,这个组件默认是全屏的(不会覆盖原生头和原生导航)。
使用plus
代码获得当前webview
的对象后(参考此文https://ask.dcloud.net.cn/article/35036),再获取子webview
,其实也可以得到web-view
组件所对应的plus
的webview
对象,进而再使用plus.webview
的丰富api
。
获取子webview
时注意时机,获取方法执行太早可能获取不到。
uni-app向内嵌网页发消息:
const
_funName='msgFromUniapp',
_data = {
msg:'msg from uniapp'
};
const currentWebview = this.$scope.$getAppWebview().children()[0];
currentWebview.evalJS(`${_funName}(${JSON.stringify(_data)})`);
内嵌网页接收消息:
<script type="text/javascript" src="https://gitee.com/dcloud/uni-app/raw/dev/dist/uni.webview.1.5.3.js">
window.msgFromUniapp= function(arg) {
console.log(arg);
console.log(JSON.stringify(arg));
}
在web-view
访问的网页内引入uni.webview.1.5.3.js
,待sdk
加载完毕后就可以调用方法postMessage
。如下:
// index.html
DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<script type="text/javascript" src="https://gitee.com/dcloud/uni-app/raw/dev/dist/uni.webview.1.5.3.js">
script>
head>
<body>
<script>
// 等待sdk加载
document.addEventListener('UniAppJSBridgeReady', function() {
// 向应用发送消息
uni.postMessage({
data: {
order: 'playRecord'
}
});
});
script>
body>
html>
uni-app接收消息
在web-view
存在的组件内写监听message
的方法。如下:
<template>
<web-view @message="message" src="/hybrid/html/index.html"></web-view>
</template>
<script>
export default {
data() {
return {};
},
methods: {
message(arg) {
console.loh(arg)
},
}
};
</script>
内嵌H5网页代码:
DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<script type="text/javascript" src="https://gitee.com/dcloud/uni-app/raw/dev/dist/uni.webview.1.5.3.js">
script>
head>
<body>
<script>
// 等待sdk加载
document.addEventListener('UniAppJSBridgeReady', function() {
// 向应用发送消息
uni.postMessage({
data: {
order: 'playRecord'
}
});
});
window.msgFromUniapp = function(arg) {
console.log(JSON.stringify(arg));
}
script>
body>
html>
uniapp组件代码:
<template>
<web-view @message='message' src="/hybrid/html/index.html"></web-view>
</template>
<script>
export default {
methods: {
message(arg) {
console.log(JSON.stringify(arg))
this.sendMsgToWebview()
},
sendMsgToWebview() {
const
_funName = 'msgFromUniapp',
_data = {
msg: 'msg from uniapp'
};
const currentWebview = this.$scope.$getAppWebview().children()[0];
currentWebview.evalJS(`${_funName}(${JSON.stringify(_data)})`);
}
}
};
</script>