1.默认30秒超时,超时后调用cameraContext.stopRecord时,stopRecord回调不会触发,最高timeout设置60秒
2.录制后的视频在真机看时是.video后缀,实际上传给后端时是类似:0.dc。后端可直接改后缀为mp4格式,因为文件mime类型还是mp4。
3.持久化存储或前端重命名时调用saveFile会报错10024:指定的路径没有写权限,我也不知道为啥,保存图片则没问题。我用copyFile解决。
4.copyFile最大只能复制30M的文件,超过会报错。持久化存储后需要注意删除文件,getFileSystemManager最多只能保存200M,只有主动删除或删除小程序时才会清除持久化的文件
uni代码示例:
bash
<camera
id="camera"
output-dimension="720P"
class="camera-view"
device-position="back"
flash="off"
@error="onCameraError"
></camera>
const startRecording = async () => {
if (!cameraContext) {
// #ifdef MP-ALIPAY
cameraContext = my.createCameraContext("camera");
// #else
cameraContext = uni.createCameraContext();
// #endif
}
isRecording.value = true;
recordingTime.value = 0;
recordingTimeText.value = '00:00';
// console.log('开始录制视频');
cameraContext.startRecord({
timeout: 600, // camera支付宝最多只能拍摄10分钟,微信5分钟,单位秒
success: () => {
// console.log('正在录制视频');
startTimer();
},
fail: () => {
// console.error('Start record fail:', e);
isRecording.value = false;
},
timeoutCallback: () => {
// console.log('Recording timeout');
isRecording.value = false;
uni.showToast({ title: '录制超时', icon: 'none' });
}
});
};
const stopRecording = () => {
if (!cameraContext) return;
cameraContext.stopRecord({
// compressed: true,
success: (res: any) => {
console.log('录制视频信息:', res)
isRecording.value = false;
stopTimer();
handleRecordedVideo(res.tempVideoPath);
// handleRecordedVideo(res.tempVideoPath.replace(".video", ".mp4"));
},
fail: (e: any) => {
console.error('Stop record fail', e);
uni.showToast({ title: e.message || '停止录制失败', icon: 'none' });
}
});
};
// 保存临时文件到本地持久化路径
export const saveTempToLocal = (tempFilePath: string, fileType?: string): Promise<string> => {
console.log('保存临时文件到本地', tempFilePath, fileType);
return new Promise((resolve, reject) => {
// 获取原始后缀
const extIndex = tempFilePath.lastIndexOf('.');
let ext = tempFilePath.substring(extIndex).toLowerCase();
// 处理支付宝小程序临时文件后缀问题
// 支付宝拍照返回的临时文件可能是 .image 后缀,需要根据文件类型转换
const invalidExts = ['.image', '.temp', '.tmp', '.video'];
if (invalidExts.includes(ext)) {
// 根据文件类型设置正确的后缀
if (fileType === 'video') {
ext = '.mp4';
} else {
ext = '.jpg';
}
}
const fileName = `upload_${Date.now()}_${Math.random().toString(36).slice(2)}${ext}`;
const newPath = `${my.env.USER_DATA_PATH}/upload_${Date.now()}.mp4`;
//#ifdef MP-ALIPAY
// 支付宝小程序使用 my.getFileSystemManager
const fs = my.getFileSystemManager();
const targetPath = `${my.env.USER_DATA_PATH}/${fileName}`;
if (fileType === 'video') {
// 由于视频调用saveFile会报错10024:指定的路径没有写权限,所以这里使用copyFile保存
fs.copyFile({
srcPath: tempFilePath,
destPath: newPath,
success: () => {
console.log('视频复制后路径', newPath);
resolve(newPath);
},
fail: (err: any) => {
if (err.error == 10028) {
// IOS超过30M无法复制
uni.showToast({ title: '视频文件过大,无法保存', icon: 'none' });
} else {
uni.showToast({ title: err.message || '处理视频文件失败', icon: 'none' });
}
console.error('复制视频文件失败:', err);
reject(err);
}
});
} else {
fs.saveFile({
tempFilePath: tempFilePath,
filePath: targetPath,
success: (res: any) => {
console.log('文件保存成功', res.savedFilePath, tempFilePath, targetPath);
resolve(res.savedFilePath);
},
fail: (err: any) => {
console.error('文件保存失败', err, tempFilePath, targetPath);
uni.showToast({ title: err.message || '文件保存失败', icon: 'none' });
reject(err);
}
});
}
//#endif
//#ifdef MP-WEIXIN
// 微信小程序使用 uni.saveFile
uni.saveFile({
tempFilePath: tempFilePath,
success: (res) => {
console.log('文件保存成功', res.savedFilePath);
resolve(res.savedFilePath);
},
fail: (err) => {
console.error('文件保存失败', err);
reject(err);
}
});
//#endif
//#ifndef MP-ALIPAY
//#ifndef MP-WEIXIN
// 其他平台先直接返回临时路径
console.warn('当前平台不支持临时文件持久化,直接使用临时路径');
resolve(tempFilePath);
//#endif
//#endif
});
}
// 删除本地持久化文件
export const deleteLocalFile = (filePath: string): Promise<void> => {
return new Promise((resolve, reject) => {
try {
//#ifdef MP-ALIPAY
const fs = my.getFileSystemManager();
fs.unlink({
filePath: filePath,
success: () => {
console.log('文件删除成功', filePath);
resolve();
},
fail: (err: any) => {
console.error('文件删除失败', err);
reject(err);
}
});
//#endif
//#ifdef MP-WEIXIN
uni.removeSavedFile({
filePath: filePath,
success: () => {
console.log('文件删除成功', filePath);
resolve();
},
fail: (err) => {
console.error('文件删除失败', err);
reject(err);
}
});
//#endif
//#ifndef MP-ALIPAY
//#ifndef MP-WEIXIN
// 其他平台不做删除操作
resolve();
//#endif
//#endif
} catch (error) {
console.error('删除本地文件失败', error);
reject(error);
}
});
}