更新记录

0.1.0(2026-09-06)

  • 插件版本更新为 0.1.0,未新增或修改运行能力。
  • 补充核心特性、平台支持、安装权限、完整接口、参数、事件、结果、状态和错误码表格。
  • 补充推荐参数、输出路径、文件提交、生命周期、常见问题、隐私合规和真机验收说明。
  • 明确区分源码已实现、编译已通过与自定义基座真机已验证,未提前宣传规划能力。
  • 修正示例页在自定义导航模式下的状态栏避让和长页面滚动。

平台兼容性

uni-app x(4.0)

Chrome Safari Android Android插件版本 iOS iOS插件版本 鸿蒙 微信小程序
× × 8.0 0.1.0 13 0.1.0 × ×

专业录音与实时音频采集

xs-audio-capture-pro 是面向 uni-app x App 的本地录音 UTS 插件。它用一套接口封装 Android 与 iOS 的麦克风权限、M4A/AAC 录音、暂停继续、停止取消、状态变化和实时音量事件。

当前版本:0.1.0

当前版本已通过 Android、iOS 插件模块和示例项目编译,但尚未完成包含本插件的双端自定义基座真机验收。本文把“源码已实现”“编译已通过”和“真机已验证”分开说明,不用编译结果代替真机录音结论。

核心特性

能力 说明
双端统一接口 Android 8.0 及以上、iOS 13.0 及以上使用相同的 UTS 类型、控制方法和回调结构
本地文件录音 生成 M4A 容器、AAC 编码的本地音频文件,不依赖网络或云服务
完整会话控制 支持开始、暂停、继续、停止和取消;同一时刻只允许一个录音会话
明确状态机 持续返回准备中、录音中、已暂停、停止中、已完成、已取消和失败状态
实时音量 按配置间隔返回 0~1 归一化振幅、近似分贝和有效录音时长
参数可配置 支持采样率、声道数、编码码率、输出路径和音量事件间隔
文件安全提交 录音过程写入隐藏临时文件,正常停止后才提交最终文件;取消或失败会清理临时文件
防止误覆盖 目标文件已经存在时返回写入错误,不会静默覆盖原文件
iOS 中断感知 iOS 可返回系统音频中断和输入路由变化事件;中断开始会暂停录音
本地与离线 插件本身不联网、不上传、不转写,也不内置广告或统计组件

平台支持

开发环境

项目 要求
开发框架 uni-app x App
HBuilderX 5.0 及以上
uni-app x 4.0 及以上
Android Android 8.0 / API 26 及以上
iOS iOS 13.0 及以上

能力差异

项目 Android iOS
最低系统版本 Android 8.0 / API 26 iOS 13.0
原生录音器 MediaRecorder AVAudioRecorder
输出格式 M4A / AAC M4A / AAC
暂停与继续 支持 支持
音量事件 支持 支持
系统中断事件 暂未接入 支持
输入路由变化事件 暂未接入 支持
后台录音 暂不支持 暂不支持
网络依赖

插件只面向 App 原生平台,不支持网页、小程序和鸿蒙平台。

安装与运行

将插件目录放到项目的 uni_modules/xs-audio-capture-pro 后,从插件根目录导入公开接口:

import {
  getAudioCaptureCapabilities,
  getAudioCapturePermission,
  requestAudioCapturePermission,
  startAudioCapture,
  pauseAudioCapture,
  resumeAudioCapture,
  stopAudioCapture,
  cancelAudioCapture
} from '@/uni_modules/xs-audio-capture-pro'

不要从 utssdk 或平台子目录导入内部实现,否则后续升级可能失去兼容性。

原生权限配置

插件自带以下原生声明:

平台 声明 用途
Android android.permission.RECORD_AUDIO 申请麦克风录音权限
Android 麦克风硬件为非必需特性 不因设备无麦克风而阻止安装
iOS NSMicrophoneUsageDescription 向用户解释麦克风用途

标准基座不包含本插件的原生代码和权限配置。真机调试前需要制作包含本插件的自定义基座,再在真实 Android、iPhone 设备上检查权限弹窗、录音文件和音频中断行为。

快速开始

下面示例先在用户点击后申请权限,再开始录音。业务页面应保存返回的会话编号,并通过同一个编号控制本次录音。

import {
  requestAudioCapturePermission,
  startAudioCapture,
  pauseAudioCapture,
  resumeAudioCapture,
  stopAudioCapture,
  cancelAudioCapture
} from '@/uni_modules/xs-audio-capture-pro'

let currentSessionId = ''

function beginRecord() {
  requestAudioCapturePermission((status) => {
    if (status != 'granted') {
      console.log('用户未授予麦克风权限')
      return
    }

    currentSessionId = startAudioCapture({
      format: 'm4a-aac',
      sampleRate: 16000,
      channels: 1,
      bitRate: 64000,
      outputPath: null,
      meterIntervalMs: 100,
      allowBackground: false
    }, (event) => {
      if (event.type == 'state') {
        console.log('状态变化', event.previousState, event.state, event.reason)
      } else if (event.type == 'meter') {
        console.log('录音时长', event.durationMs, '当前音量', event.amplitude)
      } else if (event.type == 'warning') {
        console.log('非致命提醒', event.reason)
      }
    }, (result) => {
      currentSessionId = ''
      console.log('录音文件', result.filePath)
      console.log('文件大小', result.fileSize)
      console.log('有效时长', result.durationMs)
    }, (error) => {
      currentSessionId = ''
      console.error(error.code, error.message, error.nativeCode)
    })
  }, (error) => {
    console.error(error.code, error.message)
  })
}

function pauseRecord() {
  if (currentSessionId.length > 0) pauseAudioCapture(currentSessionId)
}

function resumeRecord() {
  if (currentSessionId.length > 0) resumeAudioCapture(currentSessionId)
}

function finishRecord() {
  if (currentSessionId.length > 0) stopAudioCapture(currentSessionId)
}

function discardRecord() {
  if (currentSessionId.length > 0) cancelAudioCapture(currentSessionId)
}

接口总览

接口 返回值 说明
getAudioCaptureCapabilities() AudioCaptureCapabilities 同步获取当前平台真实能力和参数范围
getAudioCapturePermission() AudioCapturePermissionStatus 同步查询麦克风权限,不弹出系统授权框
requestAudioCapturePermission(onSuccess, onFail) void 由明确的用户操作触发麦克风权限申请
startAudioCapture(options, onEvent, onSuccess, onFail) string 创建录音会话,成功开始时返回会话编号
pauseAudioCapture(sessionId) void 暂停录音,有效录音时长停止累加
resumeAudioCapture(sessionId) void 从暂停状态继续录音
stopAudioCapture(sessionId) void 正常结束、提交文件并调用成功回调
cancelAudioCapture(sessionId) void 取消会话、删除临时文件,不产生成功结果

能力查询

getAudioCaptureCapabilities()

同步返回当前运行平台的能力,不申请权限,也不启动录音。建议在页面初始化时读取它,不要根据系统名称自行猜测能力。

字段 类型 当前值或含义
platform string androidios
available boolean 当前平台实现是否可用;双端当前均返回 true
minimumSystemVersion string 当前实现要求的最低系统版本
formats string[] 当前仅包含 m4a-aac
sampleRates number[] 公开支持的采样率列表
channelCounts number[] 当前为单声道和双声道
pauseResume boolean 是否支持暂停与继续,当前为 true
meter boolean 是否支持音量事件,当前为 true
pcmFrames boolean 是否支持实时 PCM 帧,当前为 false
vad boolean 是否支持语音活动检测,当前为 false
segmentation boolean 是否支持自动分片,当前为 false
backgroundRecording boolean 是否支持后台录音,当前为 false
recovery boolean 是否支持异常退出后的片段恢复,当前为 false
offline boolean 是否可在不联网时工作,当前为 true

权限接口

getAudioCapturePermission()

返回值 说明
notDetermined 尚未向用户询问;当前主要由 iOS 准确返回
granted 已获得麦克风权限
denied 权限被拒绝,或 Android 当前处于未授权状态

Android 的同步权限接口不能稳定区分“从未申请”和“已经拒绝”,因此未授权时统一返回 denied。不要在页面加载时自动申请权限,应在用户点击录音或授权按钮后调用权限申请接口。

requestAudioCapturePermission(onSuccess, onFail)

参数 类型 说明
onSuccess (status) => void 权限流程正常结束时调用;用户拒绝也会通过 status = denied 返回
onFail (error) => void 权限流程无法启动时调用,例如 Android 取不到当前可见页面

iOS 当前实现不会主动调用权限申请的失败回调;授权结果统一通过成功回调返回。

开始录音

startAudioCapture(options, onEvent, onSuccess, onFail)

创建唯一录音会话。正常开始后返回非空 sessionId;参数校验、权限或启动失败时返回空字符串,并调用 onFail

录音参数

当前所有字段都需要显式传入,没有自动补默认值。

参数 类型 必填 建议值 说明
options.format AudioCaptureFormat m4a-aac 当前唯一支持的格式
options.sampleRate number 16000 支持 8000 / 16000 / 22050 / 32000 / 44100 / 48000
options.channels number 1 只能为 12
options.bitRate number 64000 范围 16000~320000,单位为比特每秒
options.outputPath string \| null null 最终文件路径;传空值时写入应用私有目录
options.meterIntervalMs number 100 音量事件间隔,范围 50~1000 毫秒
options.allowBackground boolean false 当前必须为 false;传 true 会返回明确错误

公开参数通过校验只表示进入原生录音器的支持范围。不同设备是否精确接受某组采样率、声道和码率,仍需读取最终文件并在真机上核对。

事件回调

onEvent 在录音过程中可被多次调用。所有事件使用同一结构,不适用的字段返回空值。

字段 类型 说明
type AudioCaptureEventType 事件类型
sessionId string 事件所属会话编号
state AudioCaptureState 事件发生时的当前状态
previousState AudioCaptureState \| null 状态事件的上一个状态,其他事件通常为空
timestampMs number 事件产生时的毫秒时间戳
durationMs number 不含暂停时段的有效录音时长
amplitude number \| null 音量事件中的归一化振幅,范围约为 0~1
decibels number \| null 音量事件中的近似 dBFS,最低截断为 -160
reason string \| null 状态原因、中断原因、路由原因或警告内容
事件类型 Android iOS 触发时机
state 支持 支持 会话状态发生变化
meter 支持 支持 录音中按配置间隔返回音量;暂停时不返回
interruption 暂不支持 支持 系统音频中断开始或结束
routeChanged 暂不支持 支持 耳机、蓝牙等输入路由变化
warning 支持 支持 无效状态控制、会话编号不匹配或非致命音量读取失败

iOS 收到系统中断开始时会把录音切换为暂停状态;中断结束只发送事件,不会自动继续,业务页面需要让用户确认后主动调用继续接口。

成功结果

只有 stopAudioCapture() 正常关闭编码器并提交最终文件后,onSuccess 才会调用一次。

字段 类型 说明
sessionId string 已完成的会话编号
filePath string 最终 M4A 文件的本地绝对路径
fileSize number 文件字节数
durationMs number 不含暂停时段的有效录音时长
format AudioCaptureFormat 当前固定为 m4a-aac
sampleRate number 本次请求使用的采样率参数
channels number 本次请求使用的声道参数
bitRate number 本次请求使用的码率参数
stoppedReason string 当前正常结束固定为 userStopped

结果中的采样率、声道和码率是传给平台录音器的参数,不等同于独立解析文件头得到的实测值。对音频参数有严格要求时,请在真机上用音频分析工具复核最终文件。

失败回调

onFail 接收结构化错误:

字段 类型 说明
code AudioCaptureErrorCode 稳定的插件错误码,适合业务分支判断
message string 面向开发者的中文错误说明
nativeCode string \| null 平台异常类别、系统错误码或目标路径;没有时为空

会话控制

接口 允许状态 结果
pauseAudioCapture(sessionId) recording 进入 paused,有效时长停止累加
resumeAudioCapture(sessionId) paused 返回 recording,有效时长继续累加
stopAudioCapture(sessionId) recordingpaused 进入 stopping,成功后进入 completed 并返回文件
cancelAudioCapture(sessionId) 当前有效会话 进入 cancelled,删除临时文件,不调用成功回调

在错误状态调用暂停、继续或停止不会抛出同步异常,而是向当前会话发送 warning。传入空编号或不匹配的编号也不会误控制其他会话;如果当前仍有活动会话,会收到 sessionIdMismatch 警告。

状态流转

空闲 -> 准备中 -> 录音中 <-> 已暂停 -> 停止中 -> 已完成
                    |          |           |
                    +----------+-----------+-> 失败
                    +-----------------------> 已取消
状态值 中文含义 说明
idle 空闲 原生会话创建前的初始状态
preparing 准备中 输出路径、音频会话和编码器正在准备
recording 录音中 正在采集并累计有效时长
paused 已暂停 暂停采集,不累计暂停时长
stopping 停止中 正在关闭编码器并提交最终文件
completed 已完成 文件已成功提交,随后调用成功回调
cancelled 已取消 临时文件已清理,不产生结果文件
failed 失败 会话失败,随后调用失败回调

输出路径与文件行为

outputPath 写法 行为
null 或空字符串 Android 写入应用私有 files/audio-capture;iOS 写入应用支持目录下的 audio-capture
相对文件路径 相对于各平台应用私有目录解析
绝对文件路径 直接使用;调用方必须保证路径位于应用可写范围
file:// 路径 解析为本地文件路径
目录路径 自动在目录内生成带时间戳和会话编号的 .m4a 文件名
文件名没有 .m4a 后缀 自动补充 .m4a 后缀
目标文件已经存在 返回 WRITE_FAILED,不会覆盖

录音过程使用与最终文件同目录的隐藏 .partial 文件。正常停止并确认文件非空后,插件才把临时文件移动为最终文件;取消或致命错误会删除临时文件。因此业务层只能在成功回调后使用、上传或播放 filePath

推荐参数

场景 采样率 声道 码率 音量间隔 说明
语音记录 16000 1 64000 100 文件较小,适合会议记录、语音备忘
日常高质量录音 44100 1 128000 100 兼顾音质和体积
双声道采集尝试 48000 2 192000 100 需要真机确认设备输入和编码器是否实际提供双声道

这些是起始建议,不是所有设备的实测保证。正式上线前应覆盖目标设备、耳机和蓝牙输入进行验证。

错误码

错误码 当前触发场景 建议处理
MICROPHONE_PERMISSION_DENIED 未获得麦克风权限就开始录音 引导用户点击授权;被永久拒绝时引导前往系统设置
INVALID_ARGUMENT 采样率、声道、码率或音量间隔超出范围 修正参数后重新创建会话
UNSUPPORTED_FORMAT 格式不是 m4a-aac 改用当前支持格式
AUDIO_SESSION_FAILED 原生音频会话启动、暂停或继续失败 记录 nativeCode,结束当前流程后提示重试
ENCODER_FAILED 原生编码器启动或运行中失败 记录设备和原生错误,避免使用未完成文件
WRITE_FAILED 目录不可写、目标已存在、文件为空或最终提交失败 更换可写且不存在的目标路径,并检查存储空间
BACKGROUND_NOT_CONFIGURED allowBackground = true 当前版本改为 false;不要把前台录音当作后台录音使用
BUSY 已有活动会话时再次开始 先停止或取消当前会话
UNSUPPORTED Android 无法取得应用上下文或当前可见页面 确认在 App 可见页面、由用户操作调用
INTERRUPTED 已预留 当前版本不会主动通过失败回调返回此码
CANCELLED 已预留 当前取消通过 cancelled 状态事件表达,不调用失败回调

页面与生命周期建议

  • 页面上持续展示当前状态、有效时长、暂停、完成和取消入口。
  • 开始按钮防止重复点击;只有拿到非空会话编号后才开放控制按钮。
  • 页面离开前根据业务语义主动停止或取消,不要让会话失去控制入口。
  • 音量事件只用于波形、动效和静音提示,不要把它当作校准声压数据。
  • 成功回调后再播放、上传或持久化路径;取消和失败都不应保留业务记录。
  • 长时间录音由业务层设置计时提醒或主动停止;当前插件没有自动限时和自动分片。

常见问题

为什么查询权限返回拒绝,但用户还没看到过弹窗?

Android 当前只能稳定判断“是否已经授权”,不能稳定区分“从未申请”和“已经拒绝”。请在用户点击按钮后调用 requestAudioCapturePermission(),不要只依赖同步查询结果决定是否允许申请。

为什么开始录音返回空字符串?

创建失败时会返回空字符串,同时调用失败回调。应优先查看 error.codeerror.messageerror.nativeCode,常见原因是权限未授权、参数不合法、已有活动会话或目标路径不可写。

为什么拿到路径后文件还不能使用?

录音中只存在隐藏临时文件。只有正常调用停止并进入成功回调后,最终文件才完成提交。不要自行拼接文件名,也不要访问 .partial 文件。

取消录音为什么没有成功或失败回调?

取消是一个正常但不产出文件的终态。插件发送 state = cancelled 事件,清理临时文件,不调用录音成功回调,也不把用户主动取消当作失败。

系统中断结束后为什么没有自动继续?

iOS 中断开始会暂停录音,中断结束只发出 interruption 事件。为避免在用户不知情时重新采集,当前需要用户确认后主动继续。

能否后台、锁屏或静默录音?

当前版本不支持后台录音,allowBackground 必须为 false。插件也不提供静默启动、隐藏通知、远程偷录或电话通话录音。

能否直接获得 PCM、波形数组或自动去掉静音?

当前不支持 PCM 帧、语音活动检测、自动分片或静音自动停止。音量事件可以驱动简单的电平动画,但不能替代原始音频帧。

插件会上传或识别录音内容吗?

不会。插件只在设备本地采集并写入文件。上传、转写、内容分析和文件保留策略都由业务项目在成功回调后自行实现。

当前限制

  • 仅支持 m4a-aac,不支持 WAV 或裸 PCM 文件。
  • 不向 UTS 层发送实时 PCM 帧。
  • 不支持语音活动检测、自动静音停止和自动分片。
  • 不支持 Android 音频焦点、音频路由变化事件。
  • 不支持后台录音、异常退出片段恢复和进程重启续录。
  • 未完成双端自定义基座真机验收,暂不能把所有设备组合描述为已验证。

验证建议

正式使用前至少完成以下真机测试:

  1. 首次授权、拒绝、永久拒绝和系统设置恢复。
  2. 开始、暂停、继续、停止和取消的完整状态流转。
  3. 默认路径、自定义路径、已存在文件和不可写路径。
  4. 系统播放器实际播放输出文件,并独立核对容器、编码、时长、采样率和声道。
  5. iOS 电话、闹钟或语音助手中断,以及有线、蓝牙输入切换。
  6. 5 分钟、30 分钟和连续 50 次会话的稳定性。
  7. 前后台切换、锁屏、磁盘不足和应用被系统终止时的边界行为。

隐私与合规

插件不会赋予业务方录音的法律许可。业务方应在录音前清晰告知相关人员录音目的、保存期限和使用范围,并遵守所在地关于同意、隐私、劳动和客户服务录音的规定。

更多文档

  • docs/API.md:完整类型、接口、回调、状态和错误说明。
  • docs/AUDIO_FORMATS.md:格式、参数组合、体积估算和音量数据说明。
  • docs/BACKGROUND_AND_PRIVACY.md:权限、前后台边界、隐私与宿主检查清单。
  • docs/FAQ.md:接入和排错问题汇总。
  • docs/TESTING.md:双端真机测试矩阵。
  • docs/VERIFICATION.md:当前已经完成与尚未完成的验证证据。

官方参考

隐私、权限声明

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

Android 和 iOS 仅在调用方明确触发后申请麦克风权限

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

仅在设备本地采集并写入调用方明确指定的音频文件;插件不联网、不上传、不内置统计

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

暂无用户评论。