设备端做录音 + 实时语音流 的踩坑总结。

uni-app 做录音,为什么拿不到实时音频帧?

在工控平板、自助终端、语音交互项目里,需求经常是这样一句话:

“录音,实时把声音发给后端做语音识别。”

听起来很合理,但只要你用过 uni.getRecorderManager,就会立刻遇到一个冷冰冰的事实:

App 端不支持实时回调,不支持录音分片。

这篇文章把 uni-app 里所有音频方案的真实能力,一次性讲清楚。


一、先说结论(避免白忙活)

方案 能否实时拿 PCM / 帧 能否存本地 适合场景
uni.getRecorderManager 录音文件上传
plus.audio.getRecorder ❌(只能轮询文件) 简单录音
原生插件(如 leven-audio) 播放 + 录音文件
WebView MediaRecorder ❌(App 里没有) 仅 H5

👉 uni-app 官方 API 里,没有任何一个能直接给你“实时音频帧”


二、uni.getRecorderManager:看起来最像,其实最坑

标准用法

const recorderManager = uni.getRecorderManager();

recorderManager.onStop(res => {
  console.log(res.tempFilePath); // 录音结束后才给你
});

recorderManager.start({
  format: 'mp3',
  sampleRate: 16000,
  frameSize: '1KB' // ⚠️ 写了也没用
});

文档里没写清楚的一行注释

recorderManager.onFrameRecorded((frameBuffer, isLastFrame) => {
  // 分片,app不支持
});

在:

  • ✅ 微信小程序:有用
  • ❌ App(Android / iOS):完全不触发

也就是说:

frameSize 在 App 端是“假参数”


三、plus.audio:原生录音,但依然是“文件模式”

plus.audio.getRecorder 是更接近 Android 原生的方案。

基本用法

const recorder = plus.audio.getRecorder();

recorder.record(
  {
    format: 'amr',
    samplerate: '8000',
    filename: '_doc/audio/' + Date.now() + '.amr'
  },
  filePath => {
    console.log('录音文件:', filePath);
  },
  err => {
    console.error(err);
  }
);

支持什么?

  • ✅ 选格式:amr / wav / aac
  • ✅ 选采样率
  • ✅ 拿到真实文件路径
  • ✅ 权限可控

不支持什么?

  • ❌ 没有 onFrame
  • ❌ 不会边录边吐 buffer

四、一种“伪实时”:轮询录音文件(能跑,但不优雅)

文档里给了一个很工控的写法:

startRealTimeCallback() {
  let lastSize = 0;

  this.intervalId = setInterval(() => {
    plus.io.resolveLocalFileSystemURL(this.audioFilePath, entry => {
      entry.file(file => {
        if (file.size > lastSize) {
          lastSize = file.size;
          this.readChunk(file);
        }
      });
    });
  }, 300);
}
readChunk(file) {
  const reader = new plus.io.FileReader();
  reader.onloadend = e => {
    const buffer = e.target.result; // ArrayBuffer
    // 发 WebSocket / 处理
  };
  reader.readAsArrayBuffer(file);
}

这是什么意思?

  • 录音 → 写文件
  • 前端定时读文件 → 发现变大了 → 读全部
  • 不是增量,是重复读

问题很明显

问题 原因
数据重复 每次都读整个文件
延迟 300ms 起步
格式难搞 AMR / AAC 不是裸 PCM
CPU 浪费 频繁 IO

👉 只适合“对实时性要求极低”的设备端场景。


五、原生插件:播放很爽,录音还是“文件模式”

文档里重点测试了这个插件:

leven-audio(DCloud 插件市场 ID: 14803)

它能做什么?

✅ 音频播放

  • 播放本地 MP3
  • 进度监听
  • seek / pause / resume

✅ 录音

  • 请求麦克风权限
  • 录音到指定目录
const recordModule = uni.requireNativePlugin('leven-audio-RecordModule');

recordModule.start({
  saveDir: '/storage/emulated/0/leven_file'
}, res => {
  console.log(res);
});

它不能做什么?

❌ 实时音频帧
❌ 录音回调 buffer
❌ 边录边推流

本质上:封装了 Android MediaRecorder,不是 AudioRecord


六、权限配置,是 80% 报错的来源

插件文档里把 Android 权限写得很全,这里直接给你一份“抄作业版”。

manifest.json(Android)

"android": {
  "permissions": [
    "android.permission.INTERNET",
    "android.permission.RECORD_AUDIO",
    "android.permission.READ_EXTERNAL_STORAGE",
    "android.permission.WRITE_EXTERNAL_STORAGE",
    "android.permission.MODIFY_AUDIO_SETTINGS"
  ],
  "permissionExternalStorage": {
    "request": "always"
  },
  "permissionPhoneState": {
    "request": "always"
  }
}

运行时权限(Android 11+ 必写)

plus.android.requestPermissions(
  ['android.permission.RECORD_AUDIO'],
  () => start(),
  () => uni.showToast({ title: '麦克风权限被拒绝', icon: 'none' })
);

七、为什么 uni-app 就是拿不到实时音频?

这不是 bug,是架构选择。

微信小程序

  • onFrameRecorded
  • 底层是微信自己改的引擎

uni-app App

  • 基于 WebView + 原生桥
  • MediaRecorder 不存在
  • 原生层只暴露了:
    • 开始
    • 停止
    • 文件路径

👉 没有暴露 AudioRecord → PCM → JSBridge 的链路


八、那设备端“实时语音识别”怎么做?

给你 3 条真实可行的路。


✅ 方案 1:录音文件 + 分段上传(最简单)

  • 每次录 3 秒
  • stop() → 拿到文件 → 上传
  • start()
recorderManager.stop();
// 等 onStop
// 上传 → 再 start

✅ 稳定
❌ 延迟 3s+


✅ 方案 2:原生插件自己写(专业)

自己写个 uts / native 插件:

  • Android:AudioRecord → PCM
  • 16kHz → 16000 × 2 × 2 = 64KB/s
  • PCM → opus → WebSocket

这是语音助手、工控终端的标准做法


✅ 方案 3:云端长语音(绕开前端)

  • 前端只负责录文件
  • 后端用阿里 / 腾讯 / 讯飞 长语音接口
  • 后端负责 VAD + 流式识别

👉 前端压力最小,成本在云端。


九、格式选择建议(别乱选)

场景 格式
语音识别 wav(16kHz / 16bit / mono)
存储省空间 aac
老 Android 兼容 amr(但识别效果差)
云端识别 wavopus

⚠️ 注意:
plus.audio 在部分设备不支持 wav,要实测。


十、总结

uni-app 能录音,但不能“流录音”。

  • uni.getRecorderManager → 文件
  • plus.audio → 文件
  • 原生插件 → 还是文件

如果你要做:

  • 实时语音交互
  • ASR 流式识别
  • 对讲系统

👉 要么接受延迟,要么写原生插件

posted on 2026-08-13 16:22  羽丫头不乖  阅读(7)  评论(0)    收藏  举报