**
工作中需要微信小程序实现录制15s视频上传,部分用户反馈无法录制视频的问题,所以在此总结一下经验
**
下面这张图片这是问题的表现,部分机型用户松开拍摄时提示未完成拍摄,导致无法上传视频。
上面的问题是使用
wx.chooseVideo({
sourceType: ['camera'],
maxDuration: 60,
camera: 'back',
success(res) {
console.log(res.tempFilePath)
}
})
wx.chooseVideo是微信官方提供的接口,不需要用户授权,可直接调用返回拍摄完的视频地址,但是部分机型使用该接口时会出现上述问题,导致无法完成拍摄。
解决方法:
使用wx.createCameraContext(),自己定义录制方法。
注意点:
1.使用该方法需要用户授权摄像头权限和麦克风权限,需要对未授权时的情况进行处理
2.startRecord和stopRecord方法注意调用时机,都不可连续调用,需要对用户连续点击的行为做处理
代码如下:
index.wxml
<view class="video">
<video wx:if="{{video}}" src="{{video}}" style="width: 100%;display: block;"></video>
<button type="primary" bindtap="checkSetting">录制视频demo</button>
</view>
index.js
const app = getApp()
Page({
data: {
video:null
},
onLoad: function(options) {
},
onShow() {
/**
* 每次进入页面判断本地是否存在录制视频地址,有则取,取完清除
*/
if (wx.getStorageSync('auth_video')) {
this.setData({
video: wx.getStorageSync('auth_video')
})
wx.removeStorageSync('auth_video')
}
},
/**
* 由于录像页面使用了camera标签,使用该标签时需要获取摄像头权限,否则无法捕捉画面
* 所以每次进入页面时先进行检验用户是否授权摄像头权限
*/
checkSetting() {
wx.getSetting({
success: (res) => {
console.log(res)
let authSetting = res.authSetting
/**
* authSetting.hasOwnProperty('scope.camera')==true 说明用户不是首次授权
* authSetting['scope.camera']==false 说明用户未允许授权
* 只有当两个条件同时满足时需要提示用户开启授权
*/
if (authSetting.hasOwnProperty('scope.camera') && !authSetting['scope.camera']) {
wx.showModal({
content: '检测到您当前未开启摄像头权限,将无法使用相机功能',
confirmText: '去开启',
success: (res) => {
if (res.confirm) {
console.log('用户点击确定')
wx.openSetting({
success(res) {
console.log(res.authSetting)
}
});
} else if (res.cancel) {
console.log('用户点击取消')
}
}
})
} else {
wx.navigateTo({
url:"../camera/camera"
})
}
}
})
}
})
camera.wxml
<view class="video">
<view wx:if="{{!video_url}}" style="position: relative;">
<cover-view class="time-container" wx:if="{{isRecording}}">
<cover-view class="time">正在录制 {{time}}s</cover-view>
</cover-view>
<cover-view class="change-btn" wx:else bindtap="changePosition">
<cover-view>点击切换{{devicePosition=='front'?'后置':'前置'}}摄像头</cover-view>
</cover-view>
<camera binderror="getError" device-position="{{devicePosition}}" style="width: 100vw;height: 100vh;"></camera>
<cover-view class="btn-container">
<cover-view class="btn-item" bindtap="back" style="background-color: #ddd;">返回</cover-view>
<cover-view class="btn-item" bindtap="record">{{isRecording?'结束录制':'点击录制'}}</cover-view>
</cover-view>
</view>
<view wx:else style="position: fixed;width: 100vw;height: 100vh;">
<video src="{{video_url}}" style="width: 100%;height: 100%;" autoplay="{{true}}" loop="{{true}}" controls="{{false}}"></video>
<cover-view class="btn-container">
<cover-view class="btn-item" bindtap="recordAgain">重新录制</cover-view>
<cover-view class="btn-item" bindtap="sureVideo">确认选择</cover-view>
</cover-view>
</view>
</view>
camera.wxss
.time-container{
position: absolute;
width: 100%;
left:0;
top: 0;
height: 240rpx;
display: flex;
justify-content: center;
align-items: center;
background-color: rgba(0,0,0,0.4);
z-index: 100;
}
.change-btn{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
display: flex;
align-items: center;
height: 100rpx;
color: #fff;
font-size: 30rpx;
padding: 0 50rpx;
border-radius: 50rpx;
z-index: 100;
background-color: rgba(0,0,0,0.5);
}
.time{
font-size: 30rpx;
color: red;
padding: 0 20rpx;
margin-top: 30rpx;
}
.btn-container{
position: absolute;
width: 100%;
padding: 0 80rpx;
box-sizing: border-box;
bottom: 160rpx;
display: flex;
justify-content: space-between;
z-index: 100;
}
.btn-item{
padding: 30rpx 0;
border-radius: 45rpx;
background-color: #FF6685;
color: #fff;
font-size: 32rpx;
text-align: center;
width: 240rpx;
}
camera.js
const app = getApp()
Page({
data: {
ctx: null,
isRecording: false,
video_url: null,
time: 0,
min_time:5, //录制视频最小时长
timer: null,
devicePosition: "back", //摄像头朝向
isStart:false, //记录用户点击开始录制的状态
isStop:false //记录用户点击结束录制的状态
},
onLoad(options) {
const ctx = wx.createCameraContext()
this.setData({
ctx
})
},
onUnload() {
clearInterval(this.data.timer)
},
//切换前置/后置摄像头
changePosition() {
this.setData({
devicePosition: this.data.devicePosition == 'back' ? 'front' : 'back'
})
},
checkSetting() {
//这里定义一个状态isStart来记录用户点击开始录制行为,待startRecord接口请求成功后还原状态
if(this.data.isStart){
return
}
this.data.isStart = true
/**
* 调用wx.createCameraContext().startRecord()方法需要获取用户麦克风权限,否则无法调用且无法录制视频
* 所以每次进入页面时先进行检验用户是否授权麦克风权限
*/
wx.getSetting({
success: (res) => {
console.log(res)
let authSetting = res.authSetting
/**
* 原理同检测摄像头权限
*/
if (authSetting.hasOwnProperty('scope.record') && !authSetting['scope.record']) {
wx.showModal({
content: '检测到您当前未开启麦克风权限,将无法录制视频',
confirmText: '去开启',
success: (res) => {
if (res.confirm) {
console.log('用户点击确定')
wx.openSetting({
success(res) {
console.log(res.authSetting)
}
});
} else if (res.cancel) {
console.log('用户点击取消')
// this.back()
}
}
})
} else {
this.startRecord()
}
}
})
},
//用户进入页面授权时点击不允许授权时触发该方法,且不允许授权后每次进入页面都会直接触发
getError() {
console.log("用户未授权使用摄像头")
this.back()
},
//点击开始录制/结束录制
record() {
if (this.data.isRecording) {
console.log("结束录制视频")
this.stopRecord()
} else {
console.log("开始录制视频")
this.checkSetting()
}
},
//开始录制
startRecord() {
this.data.ctx.startRecord({
timeoutCallback: (res) => {
/**
* 微信官方限制
* 使用该方法录制视频最多录制30s,30s后自动停止录制
* 停止录制计时
*/
console.log("30秒时间结束,自动停止录制")
console.log(res)
clearInterval(this.data.timer)
this.setData({
video_url: res.tempVideoPath,
isRecording: false
})
},
success: (res) => {
console.log(res)
this.timing()
this.setData({
isRecording: true
})
this.data.isStart = false
},
fail:(err)=>{
console.log(err)
this.data.isStart = false
}
})
},
//结束录制
stopRecord() {
//stopRecord方法不可连续调用,否则无法停止录制
//这里定义一个状态isStop来记录用户点击结束录制行为,待stopRecord接口请求成功后还原状态
if(this.data.isStop){
return
}
if(this.data.time<this.data.min_time){
wx.showToast({
title:"视频时长小于"+this.data.min_time+"秒",
icon:"none"
})
return
}
wx.showLoading({
title:"请稍候"
})
this.data.isStop = true
this.data.ctx.stopRecord({
//compressed: false, //是否压缩录完的视频
success: (res) => {
console.log(res)
clearInterval(this.data.timer)
this.setData({
video_url: res.tempVideoPath,
isRecording: false
})
this.data.isStop = false
wx.hideLoading()
},
fail(err){
console.log(err)
this.data.isStop = false
wx.hideLoading()
}
})
},
//计时
timing() {
let time = 0
//每次计时前先将页面上的时间重置为0
this.setData({
time
})
let self = this
let timer = setInterval(function() {
time++
console.log(time)
self.setData({
time
})
}, 1000)
this.setData({
timer
})
},
//重新录制
recordAgain() {
this.setData({
video_url: null
})
},
//返回上一页
back() {
wx.navigateBack()
},
//确认选择
sureVideo() {
/**
* 将录完的视频地址保存本地,返回上一页时在onShow里面判断本地是否存在录制视频的地址
*/
wx.setStorageSync('auth_video', this.data.video_url)
wx.navigateBack()
}
})
效果图: