首发于 网站源码
uni-app小程序录音上传的解决方案

uni-app小程序录音上传的解决方案

能力依赖

RecorderManager 全局唯一的 录音 管理器


录音功能的要求与限制

与当前页面其他音频播放/录音功能互斥
是否在录音中状态显示
结束/不需要录音时,回收RecorderManager对象

材料

可以/结束 录音 录音中


Codeing(结果代码直接看最后)

构造一个简单的DOM结构

<image @click="recordAction" :src="recordImg" class="record"/>

先实现 小程序 的录音功能

import iconRecord from '../../static/images/icon_record.png'
import iconRecording from '../../static/images/icon_recording.png'
// ...
data() {
    recordImg: iconRecord, // 录音按钮的图标
    rm: null, // 录音管理器
// ...
mounted() {
    if (this.rm === null) {
        // 录音管理器如果没有初始化就先初始化
        this.rm = uni.getRecorderManager()
    // 绑定回调方法
    this.rm.onStart((e) => this.onStart(e))
    this.rm.onPause((e) => this.onPause(e))
    this.rm.onResume((e) => this.onResume(e))
    this.rm.onInterruptionBegin((e) => this.onInterruptionBegin(e))
    this.rm.onInterruptionEnd((e) => this.onInterruptionEnd(e))
    this.rm.onError((e) => this.onError(e))
// ...
methods: {
    // ...
    recordAction() {
        if (this.recordImg === iconRecord) {
            // 设置格式为MP3,最长60S,采样率22050
            this.rm.start({
                duration: 600000,
                format: 'mp3',
                sampleRate: 22050,
            // 开始录音后绑定停止录音的回调方法
            this.rm.onStop((e) => this.onStop(e))
        } else if (this.recordImg === iconRecording) {
            this.rm.stop()
    onStart(e) {
        console.log('开始录音', this.question, this.subQuesIndex)
        this.recordImg = iconRecording
        console.log(e)
    onPause(e) {
        console.log(e)
        afterAudioRecord()
    onResume(e) {
        console.log(e)
    onStop(e) {
        console.log(e)
        this.recordImg = iconRecord
        // 结束录音之后上传录音
        this.uploadMp3Action(e)
    onInterruptionBegin(e) {
      console.log(e)
    onInterruptionEnd(e) {
        console.log(e)
    onError(e) {
        console.log(e)
    uploadMp3Action(e) {
        // TODO uploadMp3
},

只能同时有一个录音,与音频播放互斥

globalData中增加两个属性audioPlaying,audioRecording

// src/App.vue
export default {
    globalData: {  
        // 保证全局只有一个音频处于播放状态且录音与播放操作互斥
        audioPlaying: false,
        audioRecording: false,
    // ...
},

Util中增加判断方法

// src/lib/Util.js
// 结束录音之后释放录音能力
export function afterAudioRecord() {
    getApp().globalData.audioRecording = false
// 结束音频播放之后释放音频播放能力
export function afterAudioPlay() {
    getApp().globalData.audioPlaying = false
 * 判断是否可以录音或者播放
 * @param {string} type play | record
export function beforeAudioRecordOrPlay(type) {
    const audioPlaying = getApp().globalData.audioPlaying
    const audioRecording = getApp().globalData.audioRecording
    if (audioPlaying ||audioRecording) {
        uni.showToast({
            title: audioPlaying ? '请先暂停其他音频播放' : '请先结束其他录音',
            icon: 'none'
        return false
    } else {
        if (type === 'play') {
            getApp().globalData.audioPlaying = true
        } else if (type === 'record') {
            getApp().globalData.audioRecording = true
        } else {
            throw new Error('type Error', type)
        return true
}

改造原有recordAction方法

import { beforeAudioRecordOrPlay, afterAudioRecord} from '../../lib/Utils';
// ...
recordAction() {
-  if (this.recordImg === iconRecord) {
+  if (this.recordImg === iconRecord && beforeAudioRecordOrPlay('record')) {
        // 设置格式为MP3,最长60S,采样率22050
        this.rm.start({
            duration: 600000,
            format: 'mp3',
            sampleRate: 22050,
        // 开始录音后绑定停止录音的回调方法
        this.rm.onStop((e) => this.onStop(e))
    } else if (this.recordImg === iconRecording) {
        this.rm.stop()
+       afterAudioRecord()
},

这样就避免了多次录音


小程序录音上传

补全我们的uploadMp3Action方法,我们使用 uni-app 的uni.uploadFile()方法来上传录音文件

uploadMp3Action(e) {
    const filePath = e.tempFilePath
    const option = {
        url: 'xxx',
        filePath,
        header,
        formData: {
            filePath
        name: 'audio',
    uni.showLoading({
        title: '录音上传中...'