更新记录
1.0.1(2026-07-15)
优化
- 完善 uni-app x 与 uni-app Vue3 使用说明。
- 补充完整 API 签名、公共类型、事件结果、错误类型和后台录音配置说明。
1.0.0(2026-07-15)
新增
- 支持 uni-app x · HarmonyOS 和 uni-app Vue3 · HarmonyOS。
- 提供
createHarmonyRecorder(options)录音实例 API。 - 支持开始、暂停、恢复、停止、销毁和状态查询。
- 支持 PCM、WAV 文件输出和实际生效配置查询。
- 支持实时 PCM
ArrayBuffer分片回调及丢弃统计。 - 支持 peak、RMS、dBFS 振幅回调。
- 支持录音状态、输入设备变化、音频中断和错误事件。
- 支持麦克风权限申请和可选后台录音长时任务。
- 提供统一错误码和可控插件日志。
平台兼容性
uni-app(5.15)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | - | - | √ | - | - | - | √ |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
uni-app x(5.15)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| - | - | - | - | - | - |
hans-hm-recorder
HarmonyOS 原生录音 UTS 插件,支持 WAV / PCM 文件、实时 PCM、振幅、输入设备变化、录音中断和后台录音。
支持范围
| 项目类型 | 平台 | 支持情况 |
|---|---|---|
| uni-app | Vue3 · App HarmonyOS | ✅ |
| uni-app x | App HarmonyOS | ✅ |
| uni-app / uni-app x | Android、iOS、Web | ❌ |
环境要求:
- HBuilderX
4.61+ - HarmonyOS
5.0+
安装
将插件放到项目的 uni_modules 目录:
uni_modules/hans-hm-recorder/
页面必须从插件根目录导入,不要直接导入 utssdk 内部文件。
导入
uni-app x
在 .uvue 的 <script setup lang="uts"> 中可以同时导入函数和类型:
import {
createHarmonyRecorder,
setHarmonyRecorderLogEnabled,
HarmonyRecorder,
HarmonyRecorderOptions,
HarmonyRecorderActualConfig,
HarmonyRecorderStopResult,
HarmonyRecorderState,
HarmonyRecorderOutputFormat,
HarmonyRecorderSourceType,
HarmonyRecorderSampleFormat,
HarmonyRecorderStateResult,
HarmonyRecorderDataResult,
HarmonyRecorderAmplitudeResult,
HarmonyRecorderDeviceResult,
HarmonyRecorderInterruptionResult,
HarmonyRecorderErrorCode,
HarmonyRecorderFail,
HarmonyRecorderStateCallback,
HarmonyRecorderDataCallback,
HarmonyRecorderAmplitudeCallback,
HarmonyRecorderDeviceCallback,
HarmonyRecorderInterruptionCallback,
HarmonyRecorderErrorCallback,
CreateHarmonyRecorder,
SetHarmonyRecorderLogEnabled,
} from '@/uni_modules/hans-hm-recorder'
uni-app Vue3
普通 JavaScript 页面只需导入运行时 API:
import {
createHarmonyRecorder,
setHarmonyRecorderLogEnabled
} from '@/uni_modules/hans-hm-recorder'
快速开始
uni-app x 完整示例
<script setup lang="uts">
import {
createHarmonyRecorder,
setHarmonyRecorderLogEnabled,
HarmonyRecorder,
HarmonyRecorderOptions,
HarmonyRecorderStateResult,
HarmonyRecorderDataResult,
HarmonyRecorderAmplitudeResult,
HarmonyRecorderDeviceResult,
HarmonyRecorderInterruptionResult,
HarmonyRecorderStopResult,
HarmonyRecorderFail,
} from '@/uni_modules/hans-hm-recorder'
// 原生录音对象不要放入 reactive 或 ref。
let recorder: HarmonyRecorder | null = null
const startRecording = async () => {
const options: HarmonyRecorderOptions = {
sampleRate: 48000,
channels: 1,
sampleFormat: 's16le',
sourceType: 'mic',
outputFormat: 'wav',
emitData: false,
enableBackground: false,
}
const current = createHarmonyRecorder(options)
recorder = current
current.onStateChange((res: HarmonyRecorderStateResult) => {
console.log('state', res.previousState, '->', res.state)
})
current.onData((res: HarmonyRecorderDataResult) => {
console.log('pcm', res.sequence, res.buffer.byteLength, res.isLast)
})
current.onAmplitude((res: HarmonyRecorderAmplitudeResult) => {
console.log('amplitude', res.peak, res.rms, res.dbfs)
})
current.onDeviceChange((res: HarmonyRecorderDeviceResult) => {
console.log('device', res.deviceId, res.deviceType, res.deviceName)
})
current.onInterruption((res: HarmonyRecorderInterruptionResult) => {
console.log('interruption', res.eventType, res.forceType, res.hintType)
})
current.onError((err: HarmonyRecorderFail) => {
console.error('runtime error', err.errCode, err.errMsg, err.data)
})
try {
await current.start()
} catch (e) {
const err = e as HarmonyRecorderFail
console.error('start failed', err.errCode, err.errMsg, err.data)
}
}
const pauseRecording = async () => {
if (recorder != null) await recorder!.pause()
}
const resumeRecording = async () => {
if (recorder != null) await recorder!.resume()
}
const stopRecording = async () => {
if (recorder == null) return
try {
const result: HarmonyRecorderStopResult = await recorder!.stop()
console.log('file', result.tempFilePath)
console.log('duration', result.durationMs)
console.log('bytes', result.byteLength)
console.log('dropped', result.droppedChunkCount)
} catch (e) {
const err = e as HarmonyRecorderFail
console.error('stop failed', err.errCode, err.errMsg)
}
}
const releaseRecorder = async () => {
if (recorder == null) return
await recorder!.destroy()
recorder = null
}
setHarmonyRecorderLogEnabled(false)
onUnload(() => {
if (recorder != null) {
recorder!.destroy()
recorder = null
}
})
</script>
uni-app Vue3 完整示例
<script>
import {
createHarmonyRecorder,
setHarmonyRecorderLogEnabled
} from '@/uni_modules/hans-hm-recorder'
// UTS 原生对象不要放入 data、reactive 或 ref。
let recorder = null
export default {
onUnload() {
if (recorder) {
recorder.destroy()
recorder = null
}
},
methods: {
async startRecording() {
if (recorder) await recorder.destroy()
recorder = createHarmonyRecorder({
sampleRate: 48000,
channels: 1,
sampleFormat: 's16le',
sourceType: 'mic',
outputFormat: 'wav',
emitData: false,
enableBackground: false
})
recorder.onStateChange((res) => {
console.log('state', res.previousState, '->', res.state)
})
recorder.onAmplitude((res) => {
console.log('dbfs', res.dbfs)
})
recorder.onDeviceChange((res) => {
console.log('device', res.deviceId, res.deviceType, res.deviceName)
})
recorder.onInterruption((res) => {
console.log('interruption', res.eventType, res.forceType, res.hintType)
})
recorder.onError((err) => {
console.error('runtime error', err.errCode, err.errMsg, err.data)
})
try {
await recorder.start()
} catch (err) {
console.error('start failed', err.errCode, err.errMsg)
}
},
async stopRecording() {
if (!recorder) return
try {
const result = await recorder.stop()
console.log(result.tempFilePath, result.durationMs, result.byteLength)
} catch (err) {
console.error('stop failed', err.errCode, err.errMsg)
}
}
}
}
</script>
API 概览
createHarmonyRecorder(
options?: HarmonyRecorderOptions | null
): HarmonyRecorder
setHarmonyRecorderLogEnabled(enabled: boolean): void
录音实例提供以下方法:
interface HarmonyRecorder {
start(): Promise<void>
pause(): Promise<void>
resume(): Promise<void>
stop(): Promise<HarmonyRecorderStopResult>
destroy(): Promise<void>
getState(): HarmonyRecorderState
getActualConfig(): HarmonyRecorderActualConfig | null
onStateChange(callback: HarmonyRecorderStateCallback): void
offStateChange(callback?: HarmonyRecorderStateCallback | null): void
onData(callback: HarmonyRecorderDataCallback): void
offData(callback?: HarmonyRecorderDataCallback | null): void
onAmplitude(callback: HarmonyRecorderAmplitudeCallback): void
offAmplitude(callback?: HarmonyRecorderAmplitudeCallback | null): void
onDeviceChange(callback: HarmonyRecorderDeviceCallback): void
offDeviceChange(callback?: HarmonyRecorderDeviceCallback | null): void
onInterruption(callback: HarmonyRecorderInterruptionCallback): void
offInterruption(callback?: HarmonyRecorderInterruptionCallback | null): void
onError(callback: HarmonyRecorderErrorCallback): void
offError(callback?: HarmonyRecorderErrorCallback | null): void
}
类型定义
以下类型均可从 @/uni_modules/hans-hm-recorder 导入,以插件内的 utssdk/interface.uts 为准。
基础类型
为兼容 UTS 与 HarmonyOS ArkTS,以下公共类型实际定义为 string,业务传值仍必须使用表格列出的值。
type HarmonyRecorderState = string
type HarmonyRecorderOutputFormat = string
type HarmonyRecorderSourceType = string
type HarmonyRecorderSampleFormat = string
HarmonyRecorderState 可能值:
| 值 | 说明 |
|---|---|
idle |
空闲,尚未开始录音 |
preparing |
正在创建和启动原生录音器 |
recording |
正在录音 |
pausing |
正在暂停 |
paused |
已暂停 |
resuming |
正在恢复 |
stopping |
正在停止并完成文件 |
stopped |
已停止,可再次调用 start() |
error |
录音发生不可恢复错误 |
released |
原生资源已释放 |
HarmonyRecorderOutputFormat 可选值:
| 值 | 说明 |
|---|---|
wav |
写入带标准 44 字节文件头的 WAV 文件 |
pcm |
写入原始 S16LE PCM 文件 |
HarmonyRecorderSourceType 可选值:
| 值 | 说明 |
|---|---|
mic |
普通麦克风录音 |
voice_recognition |
语音识别场景 |
voice_message |
语音消息场景 |
voice_communication |
语音通信场景 |
unprocessed |
未处理音频 |
HarmonyRecorderSampleFormat 当前仅支持 s16le。
HarmonyRecorderOptions
type HarmonyRecorderOptions = {
sampleRate?: number
channels?: number
sampleFormat?: HarmonyRecorderSampleFormat
sourceType?: HarmonyRecorderSourceType
outputFormat?: HarmonyRecorderOutputFormat
fileName?: string
frameDurationMs?: number
amplitudeIntervalMs?: number
emitData?: boolean
enableBackground?: boolean
}
| 字段 | 类型 | 默认值 | 可选值或范围 | 说明 |
|---|---|---|---|---|
sampleRate |
number |
48000 |
16000、44100、48000 |
采样率,单位 Hz |
channels |
number |
1 |
1、2 |
声道数 |
sampleFormat |
HarmonyRecorderSampleFormat |
s16le |
s16le |
有符号 16 位小端 PCM |
sourceType |
HarmonyRecorderSourceType |
mic |
见基础类型 | 音源场景 |
outputFormat |
HarmonyRecorderOutputFormat |
wav |
wav、pcm |
输出文件格式 |
fileName |
string |
自动生成 | 纯文件名 | 不能包含 /、\ 或 ..,建议包含正确扩展名 |
frameDurationMs |
number |
40 |
20..1000 |
实时 PCM 分片目标时长,单位 ms |
amplitudeIntervalMs |
number |
100 |
50..1000 |
振幅回调间隔,单位 ms |
emitData |
boolean |
false |
true、false |
是否触发实时 PCM 数据回调 |
enableBackground |
boolean |
false |
true、false |
是否申请后台录音长时任务 |
配置只在 createHarmonyRecorder(options) 时读取。需要修改配置时,应停止并销毁旧实例,再创建新实例。
HarmonyRecorderActualConfig
type HarmonyRecorderActualConfig = {
sampleRate: number
channels: number
sampleFormat: string
sourceType: string
outputFormat: string
}
这是系统实际创建成功的配置,可能与请求值不同。录音器尚未准备成功时,getActualConfig() 返回 null。
HarmonyRecorderStopResult
type HarmonyRecorderStopResult = {
tempFilePath: string
durationMs: number
byteLength: number
droppedChunkCount: number
config: HarmonyRecorderActualConfig
}
| 字段 | 说明 |
|---|---|
tempFilePath |
录音文件的应用缓存路径 |
durationMs |
录音时长,单位 ms |
byteLength |
文件总字节数;WAV 包含文件头 |
droppedChunkCount |
页面实时 PCM 回调因背压被丢弃的累计分片数 |
config |
实际生效的录音配置 |
droppedChunkCount 只表示页面 onData 分片是否被丢弃,不表示写入录音文件的数据丢失。
事件结果类型
type HarmonyRecorderStateResult = {
state: HarmonyRecorderState
previousState: HarmonyRecorderState
}
type HarmonyRecorderDataResult = {
buffer: ArrayBuffer
sequence: number
timestampMs: number
durationMs: number
droppedChunkCount: number
isLast: boolean
}
type HarmonyRecorderAmplitudeResult = {
peak: number
rms: number
dbfs: number
timestampMs: number
}
type HarmonyRecorderDeviceResult = {
deviceId: number
deviceName: string
deviceType: string
}
type HarmonyRecorderInterruptionResult = {
eventType: string
forceType: string
hintType: string
}
HarmonyRecorderDataResult 字段:
| 字段 | 说明 |
|---|---|
buffer |
当前 S16LE PCM 分片 |
sequence |
从 0 开始递增的分片序号 |
timestampMs |
分片起始时间,基于已处理采样帧计算 |
durationMs |
当前分片时长 |
droppedChunkCount |
页面回调累计丢弃分片数 |
isLast |
是否为停止录音时发送的最后一个分片 |
HarmonyRecorderAmplitudeResult 字段:
| 字段 | 范围或说明 |
|---|---|
peak |
峰值,范围 0..1 |
rms |
均方根,范围 0..1 |
dbfs |
分贝满量程,最大 0,最小截断为 -120 |
timestampMs |
基于已处理采样帧计算的时间戳 |
中断结果的三个字段来自 HarmonyOS 音频中断事件并转换为字符串。业务应按实际设备返回值记录和处理,不要假设所有设备都返回同一组枚举文本。
错误类型
type HarmonyRecorderErrorCode =
| 9011001
| 9011002
| 9011003
| 9011004
| 9011005
| 9011006
| 9011007
| 9011008
| 9011009
| 9011010
interface HarmonyRecorderFail extends IUniError {
errCode: HarmonyRecorderErrorCode
}
常用错误字段:
| 字段 | 类型 | 说明 |
|---|---|---|
errSubject |
string |
错误主题,固定为 hans-hm-recorder |
errCode |
HarmonyRecorderErrorCode |
稳定插件错误码 |
errMsg |
string |
错误说明 |
data |
any \| null |
调试数据,可能包含操作名、原生错误和状态 |
回调类型
type HarmonyRecorderStateCallback =
(result: HarmonyRecorderStateResult) => void
type HarmonyRecorderDataCallback =
(result: HarmonyRecorderDataResult) => void
type HarmonyRecorderAmplitudeCallback =
(result: HarmonyRecorderAmplitudeResult) => void
type HarmonyRecorderDeviceCallback =
(result: HarmonyRecorderDeviceResult) => void
type HarmonyRecorderInterruptionCallback =
(result: HarmonyRecorderInterruptionResult) => void
type HarmonyRecorderErrorCallback =
(result: HarmonyRecorderFail) => void
type CreateHarmonyRecorder =
(options?: HarmonyRecorderOptions | null) => HarmonyRecorder
type SetHarmonyRecorderLogEnabled =
(enabled: boolean) => void
API 说明
createHarmonyRecorder(options)
createHarmonyRecorder(
options?: HarmonyRecorderOptions | null
): HarmonyRecorder
创建一个录音实例。省略 options 或传入 null 时使用默认配置。
非法配置不会在创建对象时静默修正,调用 start() 时会拒绝并返回错误码 9011002。同一时间只允许一个实例实际占用麦克风。
setHarmonyRecorderLogEnabled(enabled)
setHarmonyRecorderLogEnabled(enabled: boolean): void
全局开启或关闭插件内部日志,默认关闭。生产环境建议保持关闭。
实例方法
| 方法 | 允许状态 | 返回值 | 说明 |
|---|---|---|---|
start() |
idle、stopped |
Promise<void> |
请求麦克风权限并开始录音 |
pause() |
recording |
Promise<void> |
暂停采集 |
resume() |
paused |
Promise<void> |
恢复采集 |
stop() |
recording、paused |
Promise<HarmonyRecorderStopResult> |
停止并完成输出文件 |
destroy() |
任意 | Promise<void> |
释放资源并清空监听,可重复调用 |
getState() |
任意 | HarmonyRecorderState |
获取当前状态 |
getActualConfig() |
任意 | HarmonyRecorderActualConfig \| null |
获取系统实际生效配置 |
典型状态变化:
idle
-> preparing
-> recording
-> pausing -> paused
-> resuming -> recording
-> stopping -> stopped
发生异常时可能进入 error;资源释放过程中可能收到 released 状态。
所有 Promise 方法都应使用 try/catch。onError 用于接收录音过程中异步发生的运行时错误,不能替代 start()、pause()、resume()、stop() 的 Promise 错误处理。
事件说明
状态变化
const callback: HarmonyRecorderStateCallback =
(res: HarmonyRecorderStateResult): void => {
console.log(res.previousState, res.state)
}
recorder.onStateChange(callback)
recorder.offStateChange(callback)
实时 PCM
创建录音器时设置 emitData: true:
recorder.onData((res: HarmonyRecorderDataResult) => {
console.log(
res.buffer.byteLength,
res.sequence,
res.timestampMs,
res.durationMs,
res.droppedChunkCount,
res.isLast
)
})
buffer 为 S16LE PCM ArrayBuffer。不要在高频回调中执行网络请求、编码、Base64 转换、同步大文件写入或频繁页面更新。
振幅
recorder.onAmplitude((res: HarmonyRecorderAmplitudeResult) => {
console.log(res.peak, res.rms, res.dbfs, res.timestampMs)
})
振幅始终按 S16LE 的全部声道合并计算,不要求开启 emitData。
输入设备变化
recorder.onDeviceChange((res: HarmonyRecorderDeviceResult) => {
console.log(res.deviceId, res.deviceType, res.deviceName)
})
系统报告输入设备变化时触发,例如麦克风路由发生变化。
录音中断
recorder.onInterruption((res: HarmonyRecorderInterruptionResult) => {
console.log(res.eventType, res.forceType, res.hintType)
})
电话、其他音频会话或系统策略可能触发录音中断。业务应同时监听 onStateChange 和 onError 完成状态恢复或页面提示。
运行时错误
recorder.onError((err: HarmonyRecorderFail) => {
console.error(err.errCode, err.errMsg, err.data)
})
取消监听
每个 offX 方法都支持两种用法:
// 只移除指定回调,必须传入注册时的同一个函数引用。
recorder.offAmplitude(amplitudeCallback)
// 不传回调,移除该事件的全部业务监听。
recorder.offAmplitude()
destroy() 会清空该实例的全部监听。
后台录音
插件已声明以下权限:
ohos.permission.MICROPHONEohos.permission.KEEP_BACKGROUND_RUNNING
使用 enableBackground: true 前,还必须给宿主 EntryAbility 声明后台录音模式。
- 用 HBuilderX 运行一次 HarmonyOS 项目。
- 将生成的
unpackage/dist/dev/app-harmony/entry/src/main/module.json5复制到项目的harmony-configs/entry/src/main/module.json5。 - 在
EntryAbility中加入backgroundModes:
{
"name": "EntryAbility",
"backgroundModes": [
"audioRecording"
]
}
- 创建录音器时启用后台录音:
const options: HarmonyRecorderOptions = {
enableBackground: true
}
const recorder = createHarmonyRecorder(options)
await recorder.start()
录音必须由用户在前台主动触发。后台长时任务申请失败时,start() 返回 9011009。
如果不需要后台录音,保持 enableBackground: false,无需添加 audioRecording。
文件保存与播放
stop() 返回的 tempFilePath 位于应用缓存目录,可能被系统清理。需要长期保留时,应在停止录音后复制到业务目录。
outputFormat: 'wav' 的文件可以直接尝试播放:
const result: HarmonyRecorderStopResult = await recorder.stop()
const audio = uni.createInnerAudioContext()
audio.src = result.tempFilePath
audio.play()
// 页面卸载或播放完成后释放。
audio.destroy()
outputFormat: 'pcm' 返回原始 S16LE PCM,不能直接作为普通音频文件播放,需要业务自行解码或封装。
错误码
| 错误码 | 含义 | 常见处理 |
|---|---|---|
9011001 |
麦克风权限被拒绝 | 引导用户授权或打开系统设置 |
9011002 |
参数无效或设备不支持 | 检查采样率、声道、格式和文件名 |
9011003 |
当前状态不允许调用 | 根据 getState() 调整调用顺序 |
9011004 |
已有活动录音实例 | 停止并销毁其他实例 |
9011005 |
创建原生录音器失败 | 检查设备支持情况并记录 data |
9011006 |
启动或停止采集失败 | 记录错误并重新创建实例 |
9011007 |
文件打开、写入或完成失败 | 检查存储状态和错误数据 |
9011008 |
录音被中断 | 提示用户并按业务决定是否重录 |
9011009 |
后台任务启动失败 | 检查宿主 backgroundModes 配置 |
9011010 |
未分类内部错误 | 开启日志并保留 err.data 排查 |
使用注意事项
- 同一时间只允许一个录音实例采集麦克风。
- uni-app x 和 uni-app Vue3 中都不要把录音实例放入
reactive、ref或页面data。 - 先注册事件,再调用
start(),避免遗漏启动阶段的状态和设备事件。 - 每次
start()都会重新检查麦克风权限。 - 页面卸载、业务结束或异常退出录音流程时调用
destroy()。 destroy()后不要继续使用旧实例,需要录音时重新创建。getActualConfig()以系统实际结果为准。- 需要永久保存文件时,不要长期依赖缓存路径。
- 开启
emitData后应保持回调轻量,并关注droppedChunkCount。

收藏人数:
购买源码授权版(
试用
赞赏(0)
下载 382
赞赏 0
下载 12429342
赞赏 1934
赞赏
京公网安备:11010802035340号