更新记录
2.1.0(2026-04-09)
- 精简 iOS 侧
lame.xcframework,移除macOS / tvOS / Mac Catalyst非目标平台 slice,仅保留 iOS 真机与模拟器二进制,降低插件包体与发布体积。
2.0.1(2026-04-08)
- 修复 Android 在启用前台服务时录音启动时序过早的问题,改为在前台服务真正激活后继续启动录音。
- 补充 Android 录音启动诊断日志,并增强启动中取消、服务上下文获取等边界处理。
2.0.0(2026-03-23)
- 切换到 v2 入口模型,按 manager / controller 使用录音、文件、实时上传和平台控制能力,移除 v1 顶层快捷 API。
- 新增 Android 电池优化控制、文件流接口和音频转码能力。
- 修复录音、实时上传、文件流、转码和 Android 前台服务相关稳定性问题,并完成普通
uni-app/uni-app x双兼容收敛。 - README 收敛为使用文档,补充接入前提、平台差异和使用限制。
平台兼容性
uni-app(4.76)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | - | - | √ | - | √ | √ | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
uni-app x(4.76)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| - | - | √ | √ | - | - |
hens-recorder
跨端统一录音插件,提供录音、PCM 播放、文件工具、实时上传、音频转码和平台控制能力。
支持平台
- 支持:
uni-app/uni-app x的App-Android、App-iOS - 不支持:
H5、各类小程序、Harmony
接入要求
- 宿主环境要求
HBuilderX >= 3.6.8、uni-app >= 4.76、uni-app x >= 4.76。 - Android 宿主应用要求
minSdkVersion >= 24。 - iOS 宿主应用要求
deploymentTarget >= 12.0。 - 如果要在 Android 模拟器或自定义基座上调试,宿主需要包含
x86 / x86_64ABI;插件自身的 Android 配置已内置这些 ABI。 - 代码侧统一从
@/uni_modules/hens-recorder导入,不要直接引用utssdk/*。
使用前准备
- Android 侧需要录音权限;如果要做后台录音,还会用到通知、前台服务、唤醒锁和电池优化相关能力。
- iOS 侧需要麦克风权限,后台录音依赖
audio后台模式。 - 建议先调用一次
setLoggingEnabled()明确日志开关,不要依赖默认值。 - 如果页面需要按平台/能力裁剪功能,先读取
getRecorderManager().getCapabilities()、getRealtimeUploadCapabilities()、getAudioTranscodeCapabilities()。
主入口
getRecorderManager(): RecorderManager
createPcmPlayerContext(): PcmPlayerContext
getRecorderPermissionStatus(): RecorderPermissionStatus
requestRecorderPermission(options?: RequestRecorderPermissionOptions | null): void
getRecorderFileSystemManager(): RecorderFileSystemManager
createAudioTranscodeTask(options: AudioTranscodeStartOptions): AudioTranscodeTask
getAudioTranscodeCapabilities(): AudioTranscodeCapabilities
createRealtimeUploadTask(options: RealtimeUploadStartOptions): RealtimeUploadTask
getRealtimeUploadCapabilities(): RealtimeUploadCapabilities
getAudioRouteManager(): AudioRouteController
getIOSAudioSessionManager(): IOSAudioSessionController
getAndroidForegroundServiceManager(): AndroidForegroundServiceController
getAndroidBatteryOptimizationManager(): AndroidBatteryOptimizationController
setLoggingEnabled(enabled: boolean): void
isLoggingEnabled(): boolean
录音
import {
getRecorderManager,
requestRecorderPermission,
getRecorderPermissionStatus,
RequestRecorderPermissionOptions,
RecorderManagerStartOptions
} from '@/uni_modules/hens-recorder'
const recorderManager = getRecorderManager()
const status = getRecorderPermissionStatus()
if (!status.granted) {
const permissionOptions: RequestRecorderPermissionOptions = {
microphone: true,
notifications: 'auto'
}
requestRecorderPermission(permissionOptions)
}
const startOptions: RecorderManagerStartOptions = {
format: 'm4a',
quality: 'medium',
sampleRate: 44100,
numberOfChannels: 1,
encodeBitRate: 96000,
frameSize: 0,
progressIntervalMs: 200,
interruption: 'pause',
ensurePermissions: true
}
recorderManager.onError((err) => {
console.log(err.errCode, err.errMsg)
})
recorderManager.onProgress((status) => {
console.log(status.durationMs, status.filePath)
})
recorderManager.onStop((result) => {
console.log(result.actualFormat, result.autoStopReason, result.status.filePath)
})
recorderManager.start(startOptions)
说明:
RecorderManager支持start / pause / resume / stop / getState / getStatus / getCapabilities。onStart()、onPause()、onResume()、onStop()、onStateChange()适合直接驱动页面状态。frameSize > 0时可通过onFrameRecorded()拿到实时 PCM 帧和rmsLevel / peakLevel。- Android 13+ 下,
requestRecorderPermission({ notifications: 'auto' })只有在宿主targetSdkVersion >= 33时才会显式申请通知权限。 foregroundEnabled、foregroundTitle、foregroundText、foregroundChannelName、foregroundImportance只对 Android 后台录音有意义。androidAudioSource、androidEnableAEC、androidEnableNS、androidEnableAGC只在 Android 有意义;iosPreferSpeaker主要影响 iOS 共享音频路由。
PCM 播放
import {
createPcmPlayerContext,
PcmPlayerConfigureOptions,
PcmPlayerWriteOptions
} from '@/uni_modules/hens-recorder'
const player = createPcmPlayerContext()
const configureOptions: PcmPlayerConfigureOptions = {
sampleRate: 44100,
numberOfChannels: 1,
bitDepth: 16,
audioRoute: 'speaker',
iosPreferSpeaker: true
}
player.configure(configureOptions)
player.onPlay(({ state }) => console.log(state))
player.onBufferWatermarkChange((status) => {
console.log(status.level, status.bufferedDurationMs)
})
player.play()
const writeOptions: PcmPlayerWriteOptions = {
frameBuffer,
success: (result) => console.log(result.bytesWritten)
}
player.write(writeOptions)
说明:
configure()后再执行play()/write(),结束后建议调用destroy()。audioRoute当前只支持speaker/earpiece。getBufferStatus()、onBufferChange()、setBufferWatermarks()、getBufferWatermarkStatus()可用于播放调优。
文件工具
import {
getRecorderFileSystemManager,
ResolvePathOptions,
WriteFileOptions,
ReadFileOptions
} from '@/uni_modules/hens-recorder'
const fs = getRecorderFileSystemManager()
const resolveOptions: ResolvePathOptions = {
path: 'samples',
directory: true,
createDirectories: true
}
fs.resolve(resolveOptions)
const writeOptions: WriteFileOptions = {
path: 'samples/session.txt',
text: 'hello recorder',
createDirectories: true
}
fs.write(writeOptions)
const readOptions: ReadFileOptions = {
path: 'samples/session.txt',
encoding: 'utf8',
success: (result) => console.log(result.text)
}
fs.read(readOptions)
路径和调用约定:
- 空路径和普通相对路径默认锚定推荐输出目录。
- 绝对路径按原样处理,业务侧应自行约束
path来源。 write()必须二选一传text或buffer。resolve / list / read / write / delete / move / copy都沿用success / fail / complete风格。
文件流:
import {
getRecorderFileSystemManager,
OpenFileReadStreamOptions,
OpenFileWriteStreamOptions,
FileStreamReadOptions,
FileStreamWriteOptions
} from '@/uni_modules/hens-recorder'
const fs = getRecorderFileSystemManager()
const openWriteOptions: OpenFileWriteStreamOptions = {
path: 'samples/chunks.bin',
truncate: true,
createDirectories: true
}
const writeStream = fs.openWriteStream(openWriteOptions)
const writeOptions: FileStreamWriteOptions = {
buffer: frameBuffer
}
writeStream.write(writeOptions)
writeStream.flush()
writeStream.close()
const openReadOptions: OpenFileReadStreamOptions = {
path: 'samples/chunks.bin'
}
const readStream = fs.openReadStream(openReadOptions)
const readOptions: FileStreamReadOptions = {
length: 4096,
success: (result) => console.log(result.bytesRead, result.eof)
}
readStream.read(readOptions)
readStream.close()
说明:
openReadStream()/openWriteStream()仍然是同步打开。- Android 打开失败会直接同步抛业务错误;iOS 会返回
state=error的流对象,业务侧可继续在首次read()/write()时通过fail/catch读取真实错误。 - Android 文件流同步打开失败现在会尽量保留原始业务错误码,不再统一降级成普通
Error。 - 流对象支持
read / write / seek / flush / truncate / tell / getState / close。 close()幂等;关闭后再次操作会返回9010021。
音频转码
import {
createAudioTranscodeTask,
getAudioTranscodeCapabilities,
AudioTranscodeStartOptions
} from '@/uni_modules/hens-recorder'
console.log(getAudioTranscodeCapabilities())
const options: AudioTranscodeStartOptions = {
inputPath: 'samples/input.raw',
outputPath: 'samples/input-transcoded.wav',
inputFormat: 'pcm',
outputFormat: 'wav',
sampleRate: 8000,
numberOfChannels: 1,
overwrite: true,
createDirectories: true
}
const task = createAudioTranscodeTask(options)
task.onProgress((status) => {
console.log(status.progress, status.processedBytes, status.totalBytes)
})
task.onComplete((status) => {
console.log(status.outputPath, status.outputBytes)
})
task.onError((err) => {
console.log(err.errCode, err.errMsg)
})
说明:
- 具体可用路由始终以
getAudioTranscodeCapabilities()返回值为准。 pcm输入必须显式提供sampleRate和numberOfChannels。createAudioTranscodeTask()返回后如果初始化或参数校验失败,task 会直接处于error。- 当前只支持单并发任务;超出时会返回
9010032。 cancel()默认删除部分输出文件;传deletePartialFileOnCancel: false可保留残留文件。- Android / iOS 转码错误现在会尽量透传原始业务错误码;
cancel()/getStatus()命中不存在任务时统一返回9010004。 - 建议同时监听
onStateChange()与onError(),并在任务创建后主动读一次getStatus()。
实时上传
import {
createRealtimeUploadTask,
getRealtimeUploadCapabilities,
RealtimeUploadStartOptions
} from '@/uni_modules/hens-recorder'
console.log(getRealtimeUploadCapabilities())
const startOptions: RealtimeUploadStartOptions = {
url: 'ws://127.0.0.1:8080/realtime-upload',
chunkDurationMs: 200,
stopOnRecorderStop: true
}
const task = createRealtimeUploadTask(startOptions)
task.onStateChange((state, status) => {
console.log(state, status.sentChunks, status.queuedBytes)
})
task.onMessage((message) => {
console.log(message.isBinary, message.text)
})
task.onStats((status) => {
console.log(status.state, status.inFlightChunks, status.acknowledgedChunks)
})
说明:
ackStrategy: 'manual'时,需要在服务端确认后主动调用confirmChunk(sequence);需要重发时调用retryChunk(sequence)。waitForRecorder: true适合先建链再等录音;stopOnRecorderStop: true适合把上传生命周期绑定到当前录音会话。replaceExisting: true会替换已有任务;需要保留旧任务状态时不要开启。- 建议至少监听
onOpen()、onStateChange()、onError()、onClose()、onStop()。 getStatus()可回读queuedBytes / inFlightBytes / sentBytes / acknowledgedChunks / lastErrorCode。
平台控制
import {
getAudioRouteManager,
getIOSAudioSessionManager,
getAndroidForegroundServiceManager,
getAndroidBatteryOptimizationManager,
AudioRoute,
ConfigureIOSAudioSessionOptions,
ConfigureAndroidForegroundServiceOptions,
RequestIgnoreBatteryOptimizationsOptions
} from '@/uni_modules/hens-recorder'
const preferredRoute: AudioRoute = 'speaker'
getAudioRouteManager().setPreferredRoute(preferredRoute)
const iosAudioSessionOptions: ConfigureIOSAudioSessionOptions = {
category: 'playAndRecord',
mode: 'voiceChat',
options: ['allowBluetooth', 'defaultToSpeaker'],
active: true
}
getIOSAudioSessionManager().configure(iosAudioSessionOptions)
const foregroundServiceOptions: ConfigureAndroidForegroundServiceOptions = {
enabled: true,
title: '正在录音',
text: '录音正在后台进行中',
importance: 'low'
}
getAndroidForegroundServiceManager().configure(foregroundServiceOptions)
const batteryOptimizationOptions: RequestIgnoreBatteryOptimizationsOptions = {
preferDirectRequest: true
}
getAndroidBatteryOptimizationManager().requestIgnoreBatteryOptimizations(batteryOptimizationOptions)
说明:
getAudioRouteManager()当前只接受speaker/earpiece。getIOSAudioSessionManager().getStatus()可读取当前active / category / mode / options / hasCustomConfig。getIOSAudioSessionManager().configure({ active: false })可释放当前会话,configure({ reset: true })可清空自定义配置。getAndroidForegroundServiceManager().getStatus()现在会同时返回active / serviceActive / sessionActive / isRecording / isPaused / isPreparing,其中active只表示服务已起且录音已经进入recording|paused,sessionActive会把启动中的preparing也算进去。getAndroidForegroundServiceManager()只在 Android 有实际意义;iOS 返回supported = false的占位状态。getAndroidBatteryOptimizationManager()只在 Android 6.0+ 有实际意义,从系统设置页返回后建议重新getStatus()。
使用限制
- iOS 当前支持
m4a / wav / pcm / mp3 / g711a / g711u;Android 稳定支持m4a / wav / pcm / g711a / g711u,mp3只在 runtime 中 MP3 encoder 实际可用时暴露。 - iOS 流式格式当前仍以硬件输入格式采集,
sampleRate / numberOfChannels不保证完全按请求值生效。 getRealtimeUploadCapabilities():AndroidrequiresFrameSource = true;iOS 当前requiresFrameSource = false。- Android 后台录音依赖前台服务和系统省电策略,是否稳定取决于目标机型。
- Android 电池优化白名单控制只负责打开系统授权或设置页面,不会同步等待用户授权结果。

收藏人数:
购买普通授权版(
试用
赞赏(0)
下载 309
赞赏 0
下载 11595661
赞赏 1905
赞赏
京公网安备:11010802035340号