更新记录

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 xApp-AndroidApp-iOS
  • 不支持:H5、各类小程序、Harmony

接入要求

  • 宿主环境要求 HBuilderX >= 3.6.8uni-app >= 4.76uni-app x >= 4.76
  • Android 宿主应用要求 minSdkVersion >= 24
  • iOS 宿主应用要求 deploymentTarget >= 12.0
  • 如果要在 Android 模拟器或自定义基座上调试,宿主需要包含 x86 / x86_64 ABI;插件自身的 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 时才会显式申请通知权限。
  • foregroundEnabledforegroundTitleforegroundTextforegroundChannelNameforegroundImportance 只对 Android 后台录音有意义。
  • androidAudioSourceandroidEnableAECandroidEnableNSandroidEnableAGC 只在 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() 必须二选一传 textbuffer
  • 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 输入必须显式提供 sampleRatenumberOfChannels
  • 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|pausedsessionActive 会把启动中的 preparing 也算进去。
  • getAndroidForegroundServiceManager() 只在 Android 有实际意义;iOS 返回 supported = false 的占位状态。
  • getAndroidBatteryOptimizationManager() 只在 Android 6.0+ 有实际意义,从系统设置页返回后建议重新 getStatus()

使用限制

  • iOS 当前支持 m4a / wav / pcm / mp3 / g711a / g711u;Android 稳定支持 m4a / wav / pcm / g711a / g711ump3 只在 runtime 中 MP3 encoder 实际可用时暴露。
  • iOS 流式格式当前仍以硬件输入格式采集,sampleRate / numberOfChannels 不保证完全按请求值生效。
  • getRealtimeUploadCapabilities():Android requiresFrameSource = true;iOS 当前 requiresFrameSource = false
  • Android 后台录音依赖前台服务和系统省电策略,是否稳定取决于目标机型。
  • Android 电池优化白名单控制只负责打开系统授权或设置页面,不会同步等待用户授权结果。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

Android 使用录音、通知、前台服务、唤醒锁与忽略电池优化设置引导权限;iOS 使用麦克风与后台音频模式,仅用于录音/播放相关能力

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。