微信小程序web-view 外部引用h5页面调用摄像头录制视频 配有提示音

本文介绍了一个银行贷款审批项目中视频面签功能的实现过程及遇到的技术难题,包括使用微信小程序和H5页面录制视频,并解决语音提示、声音录制等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、目前的需求是什么

因为项目是银行审批贷款的,所以需要一个视频面签的功能,进入页面时,用户点击开始录制,会提示有第一个问题提示音,用户回答,点击下一个问题,会有第二个,没有问题时,会有结束录制按钮,结束后可以看回放,再点击上传就可以提交到后台了。

2、都踩了那些坑

1、小程序

因为之前没有做过视频录制,对这一块不是很熟悉,先用的是微信小程序页面内直接做的,用的是小程序内置的组件,功能完成后发现最长只能录制30秒,比较鸡肋,重新找解决方案。

2、h5语音提示

后来就想着web-view 外部引用一个h5点页面吧,然后就看到了 recordrtc 这个,发现可以用,挺好,就开始用这个,然后接下来就开始用语音提示,用的是h5,因为我手机是ios 的 ,我在我手机上边测试都是没有问题的,然后就用同时手机测了一下,发现没有声音,我的手机是正常的,后来发现 好像 h5的语音合成好像不支持安卓?换掉,用的是 百度提示的。

3、语音合成声音录制不进去,ios有时候是麦克风,有时候是听筒发音!

调用百度api后,安卓这边录制都是没有问题的,ios这边有时候是听筒发音,有时候是麦克风发音,就好奇怪,好气,后来我让后台这边调用百度api语音合成,暂存服务器,我直接获取就可以了,ok解决问题。

4、语音合成声音录制不进去。

这边声音都正常后,看录制回放的时候,发现语音提示音录制不进去,被降噪了!人傻了。
后来找了好久,发现了一个设置的地方(之前没做过这块,所以不是很懂,别喷),就是录制的时候可以在audio中设置

      captureCamera(callback) {
       navigator.mediaDevices.getUserMedia({
         audio: { volume: { min: 0.0, max: 1.0 }, noiseSuppression: false, echoCancellation: false },
         video: { facingMode: "user" }
       }).then((camera) => {
         callback(camera);
       }).catch(function (error) {
         alert('Unable to capture your camera. Please check console logs.');
         console.error(error);
       });
     },

这样声音就好了

5、以为这样这样就结束了码?没有!ios结束的时候 有时候会不能点击结束

因为我这边问题又很多个,最后发现,在4个问题的时候是可以点击结束的,在4个以上的时候是不能点击结束的,它也不报错,然后debugger,下载recordrtc .js 研究源文件代码,发现是因为在事实结束后,会有个回调函数的,但是这边是没有回调的,

 mediaRecorder.ondataavailable  //这个应该是会自己回调的,但是没有

我以为要凉了,后来找大神指点
因为我这个是官网例子改写的,用的是这样录制的

that.recorder = RecordRTC(camera, {
            //   type: 'video'
            // })

大神将这串代码改成了

           var config = {
              mimeType: 'video/webm', // vp8, vp9, h264, mkv, opus/vorbis
              audioBitsPerSecond : 256 * 8 * 1024,
              videoBitsPerSecond : 256 * 8 * 1024,
              bitsPerSecond: 256 * 8 * 1024,  // if this is provided, skip above two
              checkForInactiveTracks: true,
              timeSlice: 1000, // concatenate intervals based blobs
              ondataavailable: function() {} // get intervals based blobs
            }
            that.recorder = new MediaStreamRecorder(camera, config);

功能就可以使用了!

因为最近都是在用vue 开发,原生的都不是很熟练,所以虽然是一个单页面应用,我用的还是vue axios…别喷
上全套代码

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.bootcdn.net/ajax/libs/RecordRTC/5.6.2/RecordRTC.js"></script>
<script crossorigin="anonymous"
 integrity="sha512-qRXBGtdrMm3Vdv+YXYud0bixlSfZuGz+FmD+vfXuezWYfw4m5Ov0O4liA6UAlKw2rh9MOYULxbhSFrQCsF1hgg=="
 src="https://lib.baomitu.com/vue/2.6.14/vue.common.dev.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js"></script>
<style type="text/css">
   .demo {
   width: 80%;
   height: 20px;
   position: absolute;
   top: 480px;
   left: 6%;
   border: 2px solid #BBDEFB;
   border-radius: 8px;
 }

 .shixin {
   width: 0;
   height: 0;
   border: 8px solid transparent;
   border-bottom-color: #BBDEFB;
   position: relative;
   top: -39px;
   left: 9%;
 }

 .kongxin {
   width: 0;
   height: 0;
   border: 8px solid transparent;
   border-bottom-color: #fff;
   position: relative;
   top: -52px;
   left: 9%;
 }
 .center {
   display: flex;
   justify-content: center;
 }

 audio {
   display: none;
 }

 button {
   width: 70%;
   padding: 3px;
   background-color: #428bca;
   border-color: #357ebd;
   color: #fff;
   -moz-border-radius: 10px;
   -webkit-border-radius: 10px;
   border-radius: 15px;
   /* future proofing */
   -khtml-border-radius: 10px;
   /* for old Konqueror browsers */
   text-align: center;
   vertical-align: middle;
   border: 1px solid transparent;
   font-weight: 900;
   font-size: 125%
 }
</style>
<title></title>
</head>

<body>
<div id="app">
 <h4 class="center">视频认证</h4>
 <hr>
 <video controls autoplay playsinline ref="video" width="100%" height="400px"></video>
 <div  v-if="showIos" class="demo" style="text-align: center;">
   <span > 请点击开始按钮</span>
   <div class="shixin"></div>
   <div class="kongxin"></div>
 </div>
 <span class="center"  style="margin-top: 30px;" v-show="nextQuestion">{{value}}</span>
 <div class="center" style="margin-top: 30px;">
   <button @click="StartRecording" v-if="startRecording" size="small">开始视频认证</button>
   <button @click="StopRecording" v-else-if="stopRecording" size="small" id="btn-stop-recording">结束视频认证
   </button>
   <button @click="question(problem)" v-else-if="nextQuestion">{{nameButton}}</button>
   <button v-else>上传视频</button>
   </button>
 </div>
</div>
<script>
 new Vue({
   el: '#app',
   //model
   data: {
     nameButton: "开始提问",
     startRecording: true,
     stopRecording: false,
     nextQuestion: false,
     index: 0,
     video: null,
     value: "",
     equipmentType:"",
     videoStart: false,
     recorder: null,
     blob: "",
     showIos:false,
     problem: [
       "请问您是李先生或女士吗?您的身份证号码是11111111122吗?",
       "您此次购买的车型是奔驰E300吗?",
       "您的家人是否知晓并同意您办理的此笔个人汽车金融贷款业务?",
       "您对此笔个人汽车金融贷款业务是否仍存有异议?",
       "如您未按时足额偿还每期月供,将会产生逾期,影响您的央行征信,是否已知晓?",
       "办理此笔汽车金额贷款是您本人的真实意识表达,承诺提供资料均真实有效,若存在欺诈行为,xxxx有权以合同诈骗提报公安机关立案侦查并追究相应的法律责任,您是否已知晓?",
     ]
   },
   //函数
   mounted() {
     this.video = document.querySelector('video');
     this. detect()
   },
   methods: {
     detect() {
       var agent = navigator.userAgent.toLowerCase();
       var android = agent.indexOf("android");
       var iphone = agent.indexOf("iphone");
       var ipad = agent.indexOf("ipad");
       if (android != -1) {
         this.equipmentType = "android";
       }
       if (iphone != -1 || ipad != -1) {
         this.equipmentType = "ios";
       }
       return this.equipmentType;
     },
     question(problem) {
       this.nameButton = "下一个问题"
       this.value = problem[this.index]

       this.baiduToken(this.value)
       if (this.index < (problem.length - 1)) {
         this.index = this.index + 1
       } else {
         this.nextQuestion = false
         this.stopRecording = true
       }
     },
     baiduToken(value) {
       axios.get(`xxxxx?text=${value}`   //向后台调用获取音频路径 ,如果是测试的可以先写一个固定的本地因为路径
       ).then(response => {
         if (response.status === 200) {
           // this.src = response.data.msg
           this.Audio(response.data.msg)
         } else {
           alert(response)
         }
       })

     },
 
     Audio(src) {
       console.log("111", src)
       var audio = document.createElement('audio');
       audio.autoplay = true;
       audio.preload = true;
       audio.controls = true;
       audio.src = src;
       // this.src =
       audio.addEventListener('ended', function () {
         // 设置则播放完后移除audio的dom对象
         document.body.removeChild(audio);
       }, false);
       audio.addEventListener('error', function () {
         document.body.removeChild(audio);
         console.log('合成出错url:' + this.src + '\nAudio错误码:' + audio.error.code);
       }, false);
       audio.loop = false;
       audio.volume = 1;
       // 在body元素下apppend音频控件
       document.body.append(audio);
     },
     stopRecordingCallback() {

       this.video.src = this.video.srcObject = null;
       this.video.muted = false;
       this.video.volume = 1;
       // let Blob = this.recorder.getBlob()
       console.log("let ", this.blob)
       this.video.src = URL.createObjectURL(this.blob);
       this.recorder.camera.stop();
       this.recorder.destroy();
       this.recorder = null;
       this.stopRecording = false
       // alert("点击了3")
     },
     StartRecording() {
       if(this.equipmentType ==="ios" ){
         this.showIos = true
       }
       let that = this
       this.startRecording = false
       this.nextQuestion = true
       this.captureCamera((camera) => {
         that.video.muted = true;
         that.video.volume = 0;
         that.video.srcObject = camera;
         var config = {
           mimeType: 'video/webm', // vp8, vp9, h264, mkv, opus/vorbis
           audioBitsPerSecond : 256 * 8 * 1024,
           videoBitsPerSecond : 256 * 8 * 1024,
           bitsPerSecond: 256 * 8 * 1024,  // if this is provided, skip above two
           checkForInactiveTracks: true,
           timeSlice: 1000, // concatenate intervals based blobs
           ondataavailable: function() {} // get intervals based blobs
         }
         that.recorder = new MediaStreamRecorder(camera, config);

         that.recorder.record();
         // release camera on stopRecording
         that.recorder.camera = camera;
       });
     },
     StopRecording() {
       let that = this
       // console.log("this", this.blob)
       // console.log("1111".this.recorder.stopRecording())
       this.recorder.stop(
         function (blob) {
           // alert("222")
           console.log("this", this)
           that.blob = blob;
           // that.stopRecordingCallback()
           that.video.src = that.video.srcObject = null;
           console.log("this.video.srcObject", that.video.srcObject)
           that.video.muted = false;
           that.video.volume = 1;
           // let Blob = this.recorder.getBlob()
           console.log("let ", that.blob)
           that.video.src = URL.createObjectURL(that.blob);
           that.recorder.camera.stop();
           //that.recorder.destroy();
           that.recorder = null;
           that.stopRecording = false
         }
       )
     },

     captureCamera(callback) {
       navigator.mediaDevices.getUserMedia({
         audio: { volume: { min: 0.0, max: 1.0 }, noiseSuppression: false, echoCancellation: false },
         video: { facingMode: "user" }
       }).then((camera) => {
         callback(camera);
       }).catch(function (error) {
         alert('Unable to capture your camera. Please check console logs.');
         console.error(error);
       });
     },

   }
 })
</script>
</body>

</html>

对了,有个小bug,最后一个问题是没有显示的,有语音播报,v-if判断有点问题,你们修改吧~我懒,哈哈哈哈,

如若又描述不清楚、代码不规范之处 ,请指出,

<think>好的,我需要帮用户解决在H5中使用UniApp的WebView嵌套语音转文字功能,并嵌入到微信小程序,还要保证免费且无调用次数限制。首先,用户的需求是集成一个语音转文字的API到H5页面,然后通过UniApp的WebView嵌入到小程序里运行,同时满足免费和无限次数的要求。 首先,我得考虑如何实现语音转文字功能。用户提到要免费且无限制,所以可能需要使用浏览器自带的Web Speech API,特别是SpeechRecognition接口。这个API是免费的,但兼容性可能有问题,比如在微信内置浏览器中的支持情况。不过,微信小程序里的WebView可能基于特定内核,需要确认是否支持。 然后,关于UniApp的WebView嵌入。UniApp允许使用web-view组件来加载H5页面,但需要注意小程序的域名白名单配置。用户需要在微信小程序后台配置业务域名,否则H5页面可能无法正常加载。 接下来,兼容性问题。微信小程序WebView环境可能和普通浏览器不同,需要测试SpeechRecognition是否可用。如果不行,可能需要寻找其他方案,比如调用小程序的原生API,但这样的话可能需要使用uniapp的插件或自己开发原生模块,但用户希望保持在H5层面实现。 另外,免费和无限次数的限制可能需要完全依赖客户端本地处理,而无需服务器端处理。Web Speech API是在客户端进行语音识别的,所以不会产生服务器费用,但准确性和支持的语言可能有限。如果用户需要更准确的识别,可能需要使用云服务,但这样就会有费用和调用次数限制,不符合用户需求。 然后,权限问题。微信小程序需要获取录音权限,H5页面也需要用户的麦克风授权。在小程序中,可能需要通过uniapp的API请求用户授权,然后在WebView中通过H5的API再次请求。需要确保流程顺畅,用户不会重复授权。 还有,支付功能的问题。虽然用户当前的问题不是支付,但参考引用的资料中提到,WebView嵌入的H5不能直接使用原有支付,需要改用小程序支付。不过这个问题可能不在此次需求范围内,但需要注意其他可能需要的小程序特定功能是否需要调整。 最后,实现步骤大致是:在H5中使用Web Speech API实现语音转文字,处理兼容性问题;在UniApp中配置web-view组件加载该H5页面;配置小程序的业务域名和权限;测试在微信环境中的运行情况,处理可能的兼容性和授权问题。 需要验证的关键点包括:微信小程序WebView是否支持SpeechRecognition,如何获取用户麦克风权限,以及如何处理不同设备的兼容性问题。如果遇到不支持的情况,可能需要降级方案,比如提示用户使用其他浏览器或更新微信版本。</think>### 分步实现方案 #### 一、语音转文字功能实现 1. **使用浏览器原生API** 在H5页面中,可通过浏览器的`Web Speech API`实现语音转文字功能。此API为浏览器内置功能,无需付费且无调用次数限制。 ```javascript const recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)(); recognition.lang = 'zh-CN'; // 设置中文识别 recognition.onresult = (event) => { const transcript = event.results[0][0].transcript; console.log('识别结果:', transcript); }; recognition.start(); ``` 2. **兼容性处理** - 微信小程序WebView内核(X5内核)需支持`Web Speech API`,建议在真机测试[^1]。 - 若API不可用,需提示用户升级微信版本或切换浏览器环境。 #### 二、UniApp集成WebView 1. **配置WebView组件** 在UniApp页面中嵌入H5页面,需使用`<web-view>`标签并指定H5地址: ```vue <template> <web-view src="https://your-h5-domain.com/speech-recognition"></web-view> </template> ``` 2. **小程序域名白名单** -微信小程序后台(公众平台)的**开发管理 > 开发设置 > 业务域名**中添加H5页面的域名。 - 确保域名已配置HTTPS证书,否则无法加载[^1]。 #### 三、微信小程序权限配置 1. **麦克风权限申请** -小程序`app.json`中声明录音权限: ```json { "permissions": { "openapi": ["getRecorderManager"] } } ``` -H5页面中通过`navigator.mediaDevices.getUserMedia`请求用户麦克风授权。 #### 四、免费与无限制实现 1. **完全依赖客户端能力** `Web Speech API`的语音识别在本地完成,无需服务器交互,因此无调用次数限制且免费。 - 局限性:识别精度受环境和浏览器影响,需在代码中增加错误处理逻辑。 ```javascript recognition.onerror = (event) => { console.error('识别失败:', event.error); }; ``` #### 五、验证与调试 1. **真机测试** -微信开发者工具中开启**调试模式**,检查WebView加载状态。 - 使用真机扫描预览码,测试麦克风授权和语音识别功能。 --- ### 关键问题与风险 1. **兼容性风险** 部分安卓机型或低版本微信可能不支持`Web Speech API`,需明确兼容范围并提供降级提示(如“当前环境不支持语音功能”)。 2. **隐私政策合规** 需在小程序隐私协议中声明麦克风使用目的,并通过弹窗动态获取用户同意[^2]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值