更新记录
1.0.0(2026-10-20)
2026年10月20日首次上传
平台兼容性
uni-app(3.91)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | × | × | × | - | 5.0 | × | × |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| × | × | × | × | × | × | × | × | × | × | × | × |
sidong-voice-stream
App 端实时音频帧采集(PCM) —— 解决 uni-app 在 App 端拿不到实时音频帧的痛点。
uni.getRecorderManager() 的 onFrameRecorded / frameSize 官方标注「App 暂不支持」,只能录完整段拿到文件。
本插件用原生 AudioRecord 采集 PCM,由 JS 定时 read() 取走小块数据,即可实现:
- 流式语音识别(边说边出字 / 边录边传)
- 实时音频上传(如自定义 ASR、实时字幕)
- 实时音量/波形分析
- 边录边存(自己拼接 PCM → wav)
平台支持
| 平台 | 支持 | 说明 |
|---|---|---|
| App-Android | ✅ | 原生 AudioRecord,本插件主要实现 |
| App-iOS | ❌ | 暂未实现(isSupported() 返回 false,可自行回退到整段录音) |
| App-HarmonyOS | ❌ | 暂未实现 |
| H5 / 小程序 | ❌ | isSupported() 返回 false;H5 可用浏览器 getUserMedia,微信小程序可用 onFrameRecorded |
未实现的平台不会报错:
isSupported()返回false,请自行回退到「录音 → 上传」。兼容性说明:本插件为 UTS 插件,在 uni-app(Vue2/Vue3) 已实测;uni-app x 未做验证 (接口本身是 UTS 标准写法,但请在 uni-app x 项目里自行验证后再用于生产)。
安装
- 插件市场安装,或把
uni_modules/sidong-voice-stream放入项目。 - App 端需要麦克风权限:本插件已自带
app-android/AndroidManifest.xml(RECORD_AUDIO、MODIFY_AUDIO_SETTINGS), 运行时权限由插件内部用UTSAndroid.requestSystemPermission自动申请。 - 含原生代码,必须打自定义基座(标准基座不含插件原生实现)。
API
import { isSupported, start, read, stop, isRecording, dropped } from '@/uni_modules/sidong-voice-stream';
| 方法 | 说明 |
|---|---|
isSupported(): boolean |
当前平台是否支持 |
start(options): void |
申请麦克风权限并开始采集 |
read(): string |
取走自上次调用后新采集的裸 PCM(Base64,16bit 小端);无新数据返回 ''(非阻塞) |
stop(): void |
停止并释放(可重复调用,不抛错) |
isRecording(): boolean |
是否正在采集 |
dropped(): string |
因缓冲溢出被丢弃的字节数(诊断用) |
start(options)
| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
sampleRate |
number |
16000 |
采样率,取值 8000/11025/16000/22050/32000/44100/48000 |
audioSource |
string |
'recognition' |
'recognition'=VOICE_RECOGNITION(适合识别,一般无 AGC);'mic'=MIC(通用麦克风) |
maxBufferBytes |
number |
4194304 |
内部缓冲上限(64KB~16MB);溢出会丢弃最旧的一半 |
readChunkBytes |
number |
3200 |
原生每次读取块大小(320~64KB) |
success |
function |
- | 开始成功 |
fail |
function |
- | { errCode, errMsg } |
complete |
function |
- | 成功/失败都会调用 |
错误码
| errCode | 含义 |
|---|---|
| 1001 | 麦克风权限被拒绝 |
| 1002 | 启动录音失败(设备不支持 / 被占用) |
| 1003 | 参数不合法(sampleRate / audioSource / maxBufferBytes / readChunkBytes) |
示例:定时取帧(推荐 40ms 一次)
import { isSupported, start, read, stop, dropped } from '@/uni_modules/sidong-voice-stream';
let timer = null;
function begin() {
if (!isSupported()) {
uni.showToast({ title: '当前平台不支持', icon: 'none' });
return;
}
start({
sampleRate: 16000,
success() {
timer = setInterval(() => {
const base64 = read(); // 自上次以来新采集的 PCM(Base64)
if (!base64) return;
// TODO:把 base64 发出去(WebSocket 分帧 / 上传 / 自己拼接保存)
console.log('新帧字节数≈', Math.floor(base64.length * 3 / 4));
}, 40);
},
fail(e) {
uni.showToast({ title: e.errMsg || '无法开始录音', icon: 'none' });
}
});
}
function end() {
clearInterval(timer);
timer = null;
stop();
console.log('丢弃字节数=', dropped());
}
你也可以在
setInterval里直接对read()的结果做 base64 解码(小程序/App 可用uni.base64ToArrayBuffer), 或按固定字节数切片后再分帧(切 base64 请按 4 的整数倍 字符切,保证每片可独立解码)。
隐私与权限声明(发布时可直接填入市场表单)
1. 本插件需要申请的系统权限列表
| 权限 | 用途 | 申请时机 |
|---|---|---|
android.permission.RECORD_AUDIO |
麦克风录音:采集实时音频帧(PCM) | 仅在调用 start() 时由插件弹出系统权限申请;用户拒绝则 fail 回调返回 errCode=1001 |
android.permission.MODIFY_AUDIO_SETTINGS |
音频设置:录音相关音频参数调整 | 随录音能力一并申请 |
可选硬件特性声明(已在插件 AndroidManifest.xml 中声明,required="false"):
android.hardware.microphone —— 无麦克风的设备也可安装,但本插件功能不可用。
除以上两项外不再申请任何权限(不申请存储、网络、位置、后台服务、通知等)。
2. 本插件采集的数据、发送的服务器地址、以及数据用途说明
本插件不采集、不存储、不上传任何数据。
- 插件源码中不包含任何网络请求(无 http / WebSocket / Socket 代码),也没有内置任何服务器地址;
- 音频数据仅存在于 App 内存缓冲区(默认上限 4MB,可配置),由调用方通过
read()主动取走(Base64 字符串); 其后续用途(发送到调用方自有服务、本地保存、语音识别等)完全由调用方代码决定,与本插件无关; - 不包含任何第三方 SDK、统计、埋点或广告组件;
- 调用
stop()后立即释放录音资源并清空缓冲区。
3. 本插件是否包含广告
否。 无广告、无统计、无埋点。
合规注意事项(仅供接入方参考)
- 请先获得用户对隐私政策的同意,再调用
start():插件内直接用系统 API 申请麦克风权限, 建议调用方先通过uni.getPrivacySetting/uni.requirePrivacyAuthorize(或自有隐私弹窗)确认用户已同意, 否则可能违反「同意隐私政策前不得申请敏感权限」的合规要求。 - 后台录音限制:插件不含前台服务/保活,Android 9+ 在后台长时间录音可能被系统限制(静音或停止)。 需要长时后台录音请自行申请前台服务及相应权限。
- 未实现的平台(iOS / HarmonyOS / H5 / 小程序)
isSupported()返回false,不会申请任何权限、不会执行原生代码。 - 用户拒绝权限时请引导其到系统设置开启;插件不会反复弹窗骚扰。
使用注意
read()是拉取式:请用定时器(建议 40~100ms)及时取走,否则内部缓冲填满后会丢弃最旧数据(可用dropped()观察)。 之所以设计成拉取而不是原生回调:Kotlin 反向回调 UTS 不被官方保证,容易被 HBuilderX 升级打断;拉取式只依赖「UTS 调 Kotlin」这一稳定方向。- 音频固定为单声道 16bit 小端;
sampleRate由你指定。 - 采集线程在原生侧,
stop()会置停止标志并join(最多 500ms)后释放,可安全重复调用。 - 若需要 wav 文件:把每次
read()的 PCM 依次写入文件,最后补 44 字节 wav 头即可。 - 后台采集:Android 9+ 后台可能被系统限制(锁屏/切后台久了会静音),如需长时间后台录音请配合前台服务/保活。
常见问题
Q:为什么不用 uni.getRecorderManager().onFrameRecorded?
A:该 API 与 frameSize 官方标注「App 暂不支持」(仅部分小程序支持,且只支持 mp3)。所以 App 端要拿实时音频只能走原生采集。
Q:为什么 read() 返回 Base64 而不是 ArrayBuffer?
A:跨语言(Kotlin → UTS → JS)传二进制容易出现类型转换问题,Base64 字符串最稳;且 Base64 可直接作为文本帧发给 WebSocket 服务。
Q:iOS 什么时候支持? A:欢迎反馈需求;目前 iOS 请自行回退到整段录音方案。
许可
MIT(可自由用于商业项目)。插件内的原生实现不依赖任何第三方 SDK。

收藏人数:
购买源码授权版(
试用
使用 HBuilderX 导入示例项目
赞赏(0)
下载 0
赞赏 0
下载 12697636
赞赏 1956
赞赏
京公网安备:11010802035340号