uni-app求助,在页面中获取相机权限后video组件没有画面,退出app重进该页面才会有画面

发布于 1周前 作者 vueper 来自 Uni-App

uni-app求助,在页面中获取相机权限后video组件没有画面,退出app重进该页面才会有画面

考勤规则

基本信息

  • 开发环境: 未提及
  • 版本号: 未提及
  • 项目创建方式: 未提及

页面内容

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="Access-Control-Allow-Origin" content="*">
        <meta http-equiv="Access-Control-Max-Age" content="3600">
        <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
        <meta name="apple-mobile-web-app-capable" content="yes">
        <meta name="apple-mobile-web-app-status-bar-style" content="black">
        <title>考勤规则</title>
        <link rel="stylesheet" href="../../css/mui.min.css">
        <style>
            * {
                padding: 0;
                margin: 0;
                background-color: #172532;
            }
            .box_1_font {
                display: flex;
            }
            .box_1_font>div {
                flex: 1;
            }
            .box_3_top {
                position: relative;
                min-width: 900px;
                width: 75%;
                height: 100%;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                display: flex;
                align-items: center;
                justify-content: center;
            }
            .video_box {
                position: relative;
            }
            .video_box video {
                width: 100%;
                height: 100%;
                display: block;
                border-radius: 50%;
                overflow: hidden;
            }
            .video_box img,
            .video_box {
                width: 280px;
                height: 280px;
            }
            .video_box img {
                position: absolute;
                left: 0;
                right: 0;
                top: 0;
                bottom: 0;
                margin: auto;
                z-index: 999;
                filter: opacity(40%);
                z-index: 999
            }
            .canvas_box {
                width: 300px;
                height: 200px;
                transform: scale(0.4) rotate(0deg);
                display: none;
            }
            .mui-bar-nav {
                background-color: #172532;
                left: 0;
                top: 0;
                right: 0;
                color: #fff;
            }
            #title {
                color: white;
                background-color: #45B1F7;
            }
            .mui-bar .mui-icon {
                color: #ffffff;
            }
            .mui-bar-nav~.mui-content {
                padding-top: 60px;
            }
            #video {
                -webkit-transform: rotateY(180deg);
                transform: rotateY(180deg);
            }
            .circle-countdown {
                margin-top:20px;
                width: 45px;
                height: 45px;
                border-radius: 50%;
                border-color: #fff;
                border: 2px solid;
                display: flex;
                justify-content: center;
                align-items: center;
                font-size: 24px;
                color: white;
            }
        </style>
    </head>
    <body>
        <header class="mui-bar mui-bar-nav" style="box-shadow: none;">
            <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
            <div class="circle-countdown mui-pull-right">30</div>
        </header>
        <div class="mui-content" style="background-color: #172532;display: flex;flex-direction: column;justify-content: space-around;align-items: center;height: 80vh;">
            <div style="display: flex;flex-direction: column;justify-content: center;align-items: center;width: 100%;">
                <div style="color: #fff;padding: 10px 0;background-color: rgba(0, 0, 0, 0.45);text-align:center;margin:62px auto;border-radius: 20px;width: 73%;">请将人脸移入框内</div>
                <div class="video_box" style="background-color: rgba(181, 181, 180, 0.7);
    border-radius: 10%;">
                    <img src="../../images/face.gif" />
                    <video id="video"></video>
                </div>
                <div class="canvas_box">
                    <canvas id="qr-canvas" style="width: 100%;height: 100%;"></canvas>
                </div>
            </div>
            <div style="width: 100%;padding-bottom: 20px;">
                <div style="margin-top: 100px;margin-bottom: 20px;display: flex;align-items: center;justify-content: center;">
                <div style="background-color: white;height: 1px;width: calc((73% - 40px) / 2);"></div>
                <div style="width: 100px;color: #fff;text-align: center;font-size: 18px;">注意事项</div>
                <div style="background-color: white;height: 1px;width: calc((73% - 40px) / 2);"></div>
                </div>
                <div style="display: flex;justify-content: space-around;align-items: center;font-size: 14px;">
                    <div style="color: white;display: flex;flex-direction: column;justify-content: center;align-items: center;">
                        <img src="../../images/ic_paishe.png" style="width: 70px;height: 70px;" />
                        <div>正脸拍摄</div>
                    </div>
                    <div style="color: white;display: flex;flex-direction: column;justify-content: center;align-items: center;">
                        <img src="../../images/ic_maozi.png" style="width: 70px;height: 70px;" />
                        <div>摘下帽子</div>
                    </div>
                    <div style="color: white;display: flex;flex-direction: column;justify-content: center;align-items: center;">
                        <img src="../../images/ic_yanjing.png" style="width: 70px;height: 70px;" />
                        <div>摘下眼镜</div>
                    </div>
                </div>
            </div>
        </div>
    </body>
    <script src="../../js/mui.js"></script>
    <script src="../../js/vue.min.js"></script>
    <script src="../../js/jquery-3.1.0.js"></script>
    <script>
        // 获取摄像头权限
        function requestPermission() {
            plus.android.requestPermissions(
                ["android.permission.CAMERA"],
                function(resultObj){
                    for (var i = 0; i < resultObj.granted.length; i++ ) {
                        var grantedPermission = resultObj.granted[i];
                        console.log('已获取的权限:' + grantedPermission);
                    }
                    for (var i = 0; i < resultObj.deniedPresent.length; i++ ) {
                        var deniedPresentPermission = resultObj.deniedPresent[i];
                        console.log('拒绝本次申请的权限:' + deniedPresentPermission );
                    }
                    for (var i = 0; i < resultObj.deniedAlways.length; i++ ) {
                        var deniedAlwaysPermission = resultObj.deniedAlways[i];
                        console.log('永久拒绝申请的权限:' + deniedAlwaysPermission);
                    }
                    // 若所需权限被永久拒绝,则打开APP设置界面,可以在APP设置界面打开相应权限
                    if (resultObj.deniedAlways.length > 0) {
                        var msg = "请在应用权限里设置允许使用相机权限";
                        mui.alert(msg,"开启相机权限","去开启",function(){
                            if (mui.os.ios) {
                                plus.runtime.openURL("app-settings:CAMERA");
                            } else {
                                var main = plus.android.runtimeMainActivity();
                                var Intent = plus.android.importClass("android.content.Intent");
                                var Build = plus.android.importClass("android.os.Build");
                                var Uri = plus.android.importClass("android.net.Uri");
                                var intent = new Intent();
                                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                if (Build.VERSION.SDK_INT >= 9) { //系统8.0以上的
                                    intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
                                    intent.setData(Uri.fromParts("package", main.getPackageName(), null));
                                } else if (Build.VERSION.SDK_INT <= 8) { //系统8.0以下的
                                    intent.setAction(Intent.ACTION_VIEW);
                                    intent.setClassName("com.android.settings", "com.android.setting.InstalledAppDetails");
                                    intent.putExtra("com.android.settings.ApplicationPkgName", main.getPackageName());
                                }
                                main.startActivity(intent);
                            }
                        });
                    }
                },
                function(error){
                    console.log('申请权限错误:' + error.code + " = " + error.message);
                });
        }

        const countdownElement = document.querySelector('.circle-countdown');
        let timeLeft = 30;

        function updateCountdown() {
            if (timeLeft <= 0) {
                plus.nativeUI.toast("已超时!");
                clearInterval(interval);
                mui.back();
            } else {
                countdownElement.innerHTML = timeLeft ;
                timeLeft--;
            }
        }

        const interval = setInterval(updateCountdown, 1000);

        mui.init();
        var content = new Vue({
            el: '#box',
            data: {
                lists: []
            },
            methods: {

            },
        })
        var yhxx;
        var userxx;
        var id;
        var username;
        var apiurl = "";
        var uuidlist;
        mui.plusReady(function() {
            requestPermission()
            apiurl = plus.storage.getItem("apiurl");
            var self = plus.webview.currentWebview();
            userxx = plus.storage.getItem("userxx");
            yhxx = userxx.split("㊌");
            id = yhxx[1];
            username = yhxx[3];
            uuidlist = self.uuidlist;
            setTimeout(function() {
                drawMedia()
            }, 800);
        });

        var picflag = true;
        function drawMedia() {
            canvas1.setAttribute("width", 450); //设置canvas宽度
            canvas1.setAttribute("height", 450); //设置canvas高度
            //context1.drawImage(图片,开始截X,开始截Y,被截宽度,被截高度,画布X位置,画布Y位置,使用图片的宽,高)
            context1.drawImage(video, 0, 0, 450, 450, 0, 0, 450, 450)
            //rotate(图片,角度,canvas宽度,canvas高度,画布X位置,画布Y位置)
            var imgBase64 = canvas1.toDataURL(("image/png"))
            //console.log(imgBase64)
            if(picflag) {
                picflag = false;
                //console.log(imgBase64)
                checkface(imgBase64);
            }
        }

        function checkface(e){
            mui.ajax({
                url: apiurl + "/KQGLAction?act=checkface",
                data: {
                    "userid": id.toString(),
                    "username": username,
                    "uuidlist":uuidlist,
                    "imgBase64":e
                },
                type: "post",
                async: true,
                dataType: "json",
                success: function(text) {
                    if (text.code == '1000') {
                        plus.nativeUI.toast(text.msg);
                        setTimeout(function() {
                            mui.back();
                        }, 1000);
                    }else if(text.code == '1200') {
                        picflag = true;
                        setTimeout(function() {
                            drawMedia()
                        }, 2000);
                    } else {
                        plus.nativeUI.toast(text.msg);
                    }
                },
                error: function(xhr, type, errorThrown) {
                    plus.nativeUI.toast(errorThrown);
                }
            });
        }

        //拍照
        var video = document.querySelector('video');
        var text = document.getElementById('text');
        var canvas1 = document.getElementById('qr-canvas');
        var context1 = canvas1.getContext('2d');
        var mediaStreamTrack;

        // 一堆兼容代码
        window.URL = (window.URL || window.webkitURL || window.mozURL || window.msURL);
        if (navigator.mediaDevices === undefined) {
            navigator.mediaDevices = {};
        }
        if (navigator.mediaDevices.getUserMedia === undefined) {
            navigator.mediaDevices.getUserMedia = function(constraints) {
                var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
                if (!getUserMedia) {
                    return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
                }
                return new Promise(function(resolve, reject) {
                    getUserMedia.call(navigator, constraints, resolve, reject);
                });
            }
        }

        //摄像头调用配置
        var mediaOpts = {
            audio: false,
            video: true,
            video: {
                facingMode: "user",
                height: 450,
                width: 450
            }
        }

        // 回调
        function successFunc(stream) {
            mediaStreamTrack = stream;
            video = document.querySelector('video');
            if ("srcObject" in video) {
                video.srcObject = stream
            } else {
                video.src = window.URL && window.URL.createObjectURL(stream) || stream
            }
            video.play();
        }

        function errorFunc(err) {
            console.log(err)
        }

        // 正式启动摄像头
        var aduioclear = ''
        var audio = document.getElementById('audio')
        openMedia()

        function openMedia() {
            if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
                console.log("支持 getUserMedia 方法")
            } else {
                console.log("不支持 getUserMedia 方法")
            }
            navigator.mediaDevices.getUserMedia(mediaOpts).then(successFunc, console.log(mediaOpts)).catch(errorFunc);
        }

        //关闭摄像头
        function closeMedia() {
            mediaStreamTrack.getVideoTracks().forEach(function(track) {
                track.stop();
                context1.clearRect(0, 0, context1.width, context1.height); //清除画布
            });
        }
    </script>
</html>

1 回复

针对你提到的在uni-app中获取相机权限后,video组件没有画面的问题,这通常是由于权限获取和组件渲染时序不一致导致的。在uni-app中,确保组件在权限获取后正确渲染,可以通过监听权限状态并在权限获取成功后重新渲染或初始化组件的方式来解决。

以下是一个简化的代码示例,展示了如何在获取相机权限后确保video组件正常工作:

<template>
  <view>
    <button @click="requestCameraPermission">请求相机权限</button>
    <video
      v-if="hasCameraPermission"
      :src="cameraStream"
      autoplay
      style="width: 100%; height: auto;"
    ></video>
  </view>
</template>

<script>
export default {
  data() {
    return {
      hasCameraPermission: false,
      cameraStream: null,
    };
  },
  methods: {
    async requestCameraPermission() {
      try {
        // 假设使用uni-app的API请求权限
        const result = await uni.authorize({
          scope: 'scope.camera',
          success: () => {
            this.hasCameraPermission = true;
            this.startCamera();
          },
          fail: () => {
            console.error('相机权限请求失败');
          },
        });
      } catch (error) {
        console.error('请求相机权限时发生错误:', error);
      }
    },
    startCamera() {
      if (!this.hasCameraPermission) return;

      // 使用uni-app的API获取相机流
      uni.createCameraContext().then(context => {
        context.startRecord({
          success: () => {
            context.getVideoContext().then(videoContext => {
              this.cameraStream = videoContext.srcObject; // 假设srcObject是video流的正确属性
            });
          },
          fail: () => {
            console.error('开始相机录制失败');
          },
        });
      });
    },
  },
  onUnload() {
    // 页面卸载时停止相机,释放资源
    if (this.cameraStream) {
      // 这里需要根据实际情况添加停止相机和释放流的代码
      console.log('页面卸载,停止相机');
    }
  },
};
</script>

注意

  1. 上述代码示例假设uni.authorizeuni.createCameraContext等API的存在和用法,实际使用中需要参考uni-app官方文档调整。
  2. video组件的src属性可能需要根据实际情况调整,因为srcObject是WebRTC API中的属性,uni-app中可能有所不同。
  3. 在实际项目中,处理相机权限和流的逻辑可能更复杂,需要考虑用户拒绝权限、权限被系统收回等情况。
  4. 确保在组件销毁时正确释放相机资源,避免内存泄漏。
回到顶部