• 跨平台应用开发进阶(三十):uni-app 实现视频直播


    一、前言

    项目开发进程中,业务提出新需求,需要接入视频直播。为此,开始接触火山引擎视频直播。火山引擎方值负责提供观播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。这个子webviewappend到父webview上。

    var currentWebview = this.$scope.$getAppWebview(); //此对象相当于html5plus里的plus.webview.currentWebview()。在uni-app里vue页面直接使用plus.webview.currentWebview()无效
    currentWebview.append(wv);//一定要append到当前的页面里!!!才能跟随当前页面一起做动画,一起关闭
    
    • 1
    • 2

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    有关参数、回调函数等详细用法,详参接口文档。

    2.1 web-view组件在app中的窗体关系和plus.webview操作方式

    uni-appvue页面本身是一个webviewvue页面里的web-view组件,其实是一个子webview。但一个vue页面不能放多个web-view组件,这个组件默认是全屏的(不会覆盖原生头和原生导航)。

    使用plus代码获得当前webview的对象后(参考此文https://ask.dcloud.net.cn/article/35036),再获取子webview,其实也可以得到web-view组件所对应的pluswebview对象,进而再使用plus.webview的丰富api

    获取子webview时注意时机,获取方法执行太早可能获取不到。

    三、双向通信

    3.1 uni-app与内嵌网页通信

    uni-app向内嵌网页发消息

    const
      _funName='msgFromUniapp',
      _data = {
        msg:'msg from uniapp'
      };
    const currentWebview = this.$scope.$getAppWebview().children()[0];
    currentWebview.evalJS(`${_funName}(${JSON.stringify(_data)})`);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    内嵌网页接收消息

    <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));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    3.2 内嵌网页向uni-app发消息

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    四、实现案例

    内嵌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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    五、拓展阅读

  • 相关阅读:
    国外调查问卷项目赚美金是真的吗?
    DFS对树的遍历及一些优化
    从指针开始变强(二)之函数指针
    vscode常用快捷键(动图演示)
    神经网络模型--数学建模
    案例分享-丢失的请求头
    06-nginx反向代理实战
    李宏毅老师《机器学习》课程笔记-4.1 Self-attention
    RestCloud ETL 跨库数据聚合运算
    .NET性能优化-使用结构体替代类
  • 原文地址:https://blog.csdn.net/sunhuaqiang1/article/details/126322971