微信小程序录像功能实现:5步完成视频录制、预览与上传
微信小程序的录像功能,表面上看是调用一个API,但实际开发中,你会发现“能录像”和“录得好、录得稳、能上传”完全是两码事。我见过不少新手,照着文档写完代码,结果在iPhone上黑屏,或者在Android上录制出来的视频只有几KB。这篇文章,咱们就从头到尾把录像功能拆开揉碎了讲,重点落在那些文档里没写、但实际开发必踩的坑上。
一、录像前的准备:权限与组件选择
一上来就写 wx.startRecord,但这是旧接口,早已废弃。现在统一使用 wx.createMediaContainer 或 CameraContext。这里有个关键区别:MediaContainer 适合做视频合成(比如录像后加滤镜),而单纯录像用 CameraContext.startRecord 更轻量。
权限申请是个容易忽略的细节。小程序在iOS上需要同时勾选“相机”和“麦克风”权限,但Android上部分机型(比如小米)还需要在manifest里单独声明录音权限。如果你只勾选了相机,用户在Android上录像时,画面正常但没声音,这就是权限遗漏导致的。
举个例子,我在一个医疗问诊小程序里,用户反馈录像没声音。排查后发现,requiredPrivateInfos 里只写了 "camera",加上 "microphone" 后问题解决。代码配置如下:
// app.json
{
"requiredPrivateInfos": ["camera", "microphone"]
}
二、核心实现:从Camera组件到录像控制
Camera组件是录像的基础。但要注意,它有一个 mode 属性,默认是 "normal",如果你想录像时画面更流畅,可以改成 "scanCode" 或 "custom"。实测在低端Android机上,mode="normal" 会导致录像时画面卡顿,改成 "custom" 后帧率明显提升。
下面是录像的核心代码逻辑,注意我用了 try-catch 包裹,因为录像过程中用户可能突然切到后台,导致API调用失败:
// page.wxml
// page.js
Page({
data: {
isRecording: false,
tempVideoPath: ''
},
startRecord() {
const ctx = wx.createCameraContext('myCamera');
ctx.startRecord({
timeoutCallback: () => {
// 超过最大录制时间(默认30秒)自动停止
this.stopRecord();
},
success: () => {
this.setData({ isRecording: true });
},
fail: (err) => {
console.error('录像启动失败', err);
wx.showToast({ title: '录像启动失败', icon: 'none' });
}
});
},
stopRecord() {
const ctx = wx.createCameraContext('myCamera');
ctx.stopRecord({
compressed: true, // 压缩视频,减少体积
success: (res) => {
this.setData({
isRecording: false,
tempVideoPath: res.tempVideoPath
});
// 这里可以预览或上传
this.previewVideo(res.tempVideoPath);
},
fail: (err) => {
console.error('停止录像失败', err);
}
});
}
});
注意 compressed: true 这个参数。如果不加,录出来的视频体积会非常大,1分钟可能达到100MB以上。但压缩也会带来画质损失,如果你的场景需要高清录像(比如教学录屏),可以设为 false,然后在上传时用后端进行压缩。
用户录像时,如果没有任何反馈,会感到迷茫。我习惯在录像时显示一个倒计时,同时用震动提示开始和结束。这里有个技巧:wx.vibrateShort 在iOS上只能调用一次,连续调用会失败,所以最好用 setInterval 控制频率。
倒计时的实现:
// 假设最大录制30秒
let remaining = 30;
this.timer = setInterval(() => {
remaining--;
if (remaining <= 0) {
clearInterval(this.timer);
this.stopRecord();
}
this.setData({ countdown: remaining });
}, 1000);
// 开始录像时震动
wx.vibrateShort({ type: 'medium' });
这里有个坑:当用户手动停止录像时,一定要清除定时器,否则界面会显示负数。我在一个社交小程序里就遇到过,用户录像10秒后手动停止,结果倒计时还在跑,显示“-20秒”,非常尴尬。
四、录像后的处理:预览与上传录完视频后,用户通常希望预览一下。用 wx.previewMedia 可以同时预览图片和视频,但注意它只支持临时路径,不支持网络路径。如果你需要用户确认后再上传,可以先用 VideoContext 播放:
previewVideo(path) {
const videoContext = wx.createVideoContext('myVideo');
this.setData({ videoPath: path }, () => {
videoContext.play();
});
}
上传视频时,用 wx.uploadFile。但视频文件通常较大,上传时间较长,最好显示一个进度条。可惜 wx.uploadFile 本身不支持进度监听,需要自己用 wx.request 配合 XMLHttpRequest 实现,或者用第三方SDK。这里有个折中方案:先压缩视频再上传,可以显著减少等待时间。
压缩视频可以用 wx.compressVideo,但注意它只支持临时路径,且压缩后的视频可能丢失音频。我在一个教育类小程序里,压缩后音频不同步,后来发现是码率设置太低,调整 bitrate 到 1Mbps 后解决:
wx.compressVideo({
src: tempVideoPath,
quality: 'medium',
bitrate: 1024, // 码率,单位kbps
success: (res) => {
// 上传压缩后的视频
this.uploadVideo(res.tempFilePath);
}
});
五、兼容性处理:各机型踩坑实录
录像功能在真机上问题最多。我整理了几个高频问题:
1. iPhone XS 及以上机型录像黑屏
原因是这些机型默认使用HEVC编码,而小程序的Camera组件在部分版本下不支持。解决方案是在 startRecord 前调用 CameraContext.setZoom 强制切换编码格式,但更简单的做法是让用户升级微信版本。
2. 华为P系列录像时画面闪烁
这是由于相机自动对焦导致的。可以在Camera组件上加 focus-distance="100" 固定焦距,或者用 flash="off" 关闭闪光灯。实测设置 auto-focus="false" 后闪烁消失。
3. 小米手机录像文件损坏
小米部分机型(如Redmi Note 10)在录像过程中如果切换前后摄像头,会导致文件无法播放。解决方案是禁止用户录像时切换摄像头,或者在切换前先停止录像。
小程序切到后台时,录像会自动停止。但用户可能有“录到一半接电话”的场景。你可以用 onHide 生命周期监听,在切后台时保存当前录像状态,返回时恢复。但注意,Camera组件在后台会被销毁,恢复时需要重新创建。
这里有个取巧的办法:用 wx.setScreenBrightness 保持屏幕常亮,减少用户切后台的概率。同时,在 onShow 里检查是否有未完成的录像,提示用户继续或放弃。
代码示例:
onHide() {
if (this.data.isRecording) {
wx.setStorageSync('pendingRecord', true);
this.stopRecord(); // 自动停止并保存临时文件
}
},
onShow() {
const pending = wx.getStorageSync('pendingRecord');
if (pending) {
wx.showModal({
title: '检测到未完成的录像',
content: '是否继续刚才的录像?',
success: (res) => {
if (res.confirm) {
// 继续录像,但需要重新创建Camera组件
this.startRecord();
}
wx.removeStorageSync('pendingRecord');
}
});
}
}
录像功能看起来简单,但真正做好,需要兼顾权限、兼容性、用户体验和异常处理。上面这些细节,是我在多个小程序项目中踩坑后总结出来的。如果你在开发中遇到其他奇怪的问题,欢迎交流——毕竟,微信小程序的坑,总是比文档里写的多那么几个。

