更新记录

1.1.0(2026-09-08)

  • fix: iOS 文件合成失败、取消或停止时正确拒绝 Promise,并保留插件错误码和错误信息。
  • fix: iOS 支持并发文件合成,默认输出路径互不覆盖;文件写入完成并关闭后才返回成功,取消后的回调不会影响新任务。
  • fix: Android 暂停期间新增朗读会继续排队;恢复时不会重复触发 onStart,并从最近的边界继续播放。
  • fix: Android 文件合成支持对生成的 WAV 应用 volume,写入或音量处理失败时 Promise 会拒绝。
  • fix: 传统 uni-app 在 HBuilderX 5.24 及以上版本中可以通过 catch 接收 Android 文件合成错误。
  • fix: Harmony 的 onDone 在整段文本播放完成后触发;连续朗读、暂停恢复和文件合成队列行为得到修正。
  • fix: Harmony 停止时会取消当前及排队中的文件合成任务,并为并发文件任务生成独立的默认路径。
  • feat: 支持音量调节(volume 0.0 ~ 1.0)在 Android 和 iOS 原生生效
  • feat: 新增国内 Android 机型 TTS 引擎检测(getEnginesAsync, isEngineAvailableAsync)与一键跳转系统设置(openTtsSettings
  • fix: Harmony resume() 现在会重新提交暂停时未播完的语句(原先静默无效),从暂停分句开头重播
  • fix: Harmony 引擎初始化并发等待改为共享 Promise,去除轮询忙等
  • fix: 三端 stop() 打断 synthesizeToFile 时现在会以失败落定 Promise(原先永久挂起)
  • fix: Android TTS 初始化失败后会释放坏实例并在下次调用时重试(原先后续 speak 永久静默挂起)
  • fix: iOS 暂停后调用 stop() 会先恢复合成器,修复之后 speak() 静音不播的问题
  • fix: Android 引擎回调 Map 改为并发安全;修复 getVoicesAsync 遇到未知 ISO3 国家码时的崩溃风险

1.0.0(2026-01-27)

  • feat: 提供语音合成(TTS)核心 API(Android/iOS)
  • feat: 新增 playground 验证页(uniappx-speech-playground/pages/index/index.uvue
  • docs: 完善使用文档与发布/实现说明

平台兼容性

uni-app(4.87)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
- -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - - -

uni-app x(4.87)

Chrome Safari Android iOS 鸿蒙 微信小程序
- - -

hans-speech

uni-app / uni-app x App 端语音合成(TTS)插件(Android / iOS / Harmony)。

平台

  • Android / iOS / Harmony:支持(App 端)
  • Web / 小程序:不支持

说明:

  • 本插件为 TTS(语音合成),不需要麦克风/语音识别权限
  • Android onBoundary 仅在 API 26+ 触发(系统限制);Harmony 暂不触发 onBoundary

安装

  • 插件市场安装后,会在项目根目录生成 uni_modules/hans-speech/
  • 或将 hans-speech 文件夹复制到你的项目 uni_modules/

引入

import {
  speak,
  stop,
  pause,
  resume,
  getAvailableVoicesAsync,
  isSpeakingAsync,
  synthesizeToFileAsync,
  maxSpeechInputLength,
  getMaxSpeechInputLength,
  setLogEnabled,
  isLogEnabled,
  getEnginesAsync,
  isEngineAvailableAsync,
  openTtsSettings,
  // 类型(仅 uni-app x 支持)
  type Voice,
  type TtsEngineInfo,
  type SpeechOptions,
  type SynthesizeToFileOptions,
  type AudioFocusMode,
  type HansSpeechError,
} from '@/uni_modules/hans-speech'

类型导入(uni-app x)

uni-app x 页面可以通过 type X 显式导入插件导出的类型,获得完整的 IDE 补全与编译期类型检查:

import {
  speak,
  getAvailableVoicesAsync,
  type Voice,
  type SpeechOptions,
} from '@/uni_modules/hans-speech'

const options: SpeechOptions = {
  language: 'zh-CN',
  onDone: () => console.log('done'),
}
speak('你好', options)

const voices: Array<Voice> = await getAvailableVoicesAsync()
const first: Voice | null = voices.length > 0 ? voices[0] : null

可导入的类型:

类型 说明
Voice 发音人:identifier / name / language / quality
TtsEngineInfo TTS 引擎信息:name / label / icon
SpeechOptions speak() 的参数(含全部回调)
SynthesizeToFileOptions synthesizeToFileAsync() 的参数
AudioFocusMode 音频焦点模式:'duck' \| 'pauseOthers' \| 'mix' \| 'none'
VoiceQuality 音质标记:'Default' \| 'Enhanced'
HansSpeechError / HansSpeechErrorCode 插件错误对象与错误码
NativeBoundaryEvent / NativeBoundaryEventCallback onBoundary 边界事件

说明:type X 导入仅 uni-app x(uts)页面支持;经典 uni-app(JS)页面直接调用函数即可,不要导入类型。

快速开始

speak('你好', {
  language: 'zh-CN',
  rate: 1.0,
  pitch: 1.0,
  onStart: () => console.log('start'),
  onDone: () => console.log('done'),
  onStopped: () => console.log('stopped'),
  onBoundary: (e) => console.log(e.charIndex, e.charLength),
  onError: (e) => console.error(e.message),
})

停止/暂停/恢复/状态:

await stop()
const speaking = await isSpeakingAsync()

await pause()
await resume()

各端 pause()/resume() 语义见下方「平台差异」。

语音列表与选择发音人

const voices = await getAvailableVoicesAsync()
const v = voices.length > 0 ? voices[0] : null

speak('Hello', {
  voice: v?.identifier ?? '',
})

Voice 字段:

  • identifier: string(用于 SpeechOptions.voice
  • name: string
  • language: string(例如 zh-CN / en-US
  • quality: string(通常为 Default / Enhanced,平台返回值可能略有差异)

speak(text, options)

SpeechOptions

  • language?: string:语言/地区(例如 zh-CN / en-US),不传则使用系统默认语言
  • rate?: number:语速,建议范围 0.1 ~ 2.0(不传则使用系统默认)
  • pitch?: number:语调,建议范围 0.5 ~ 2.0(不传则使用系统默认)
  • volume?: number:音量,范围 0.0 ~ 1.0(0.0 静音,1.0 最大音量,默认 1.0)
  • voice?: string:发音人 identifier(来自 getAvailableVoicesAsync()
  • audioFocusMode?: string:音频焦点模式 'duck' | 'pauseOthers' | 'mix' | 'none'(Android,默认 'duck'
  • useApplicationAudioSession?: boolean:仅 iOS 13+,不传则使用系统默认
  • autoChunk?: boolean:超长文本自动按句子分块播报,默认 true
  • 回调:onStart / onBoundary / onDone / onStopped / onError

说明:

  • 多次调用 speak() 会追加到队列;需要“打断并重播”请先 await stop()speak()
  • onDone 表示整段文本播放完成;暂停不会触发 onDoneonStopped,恢复不会重复触发该段文本的 onStart
  • speak() 的错误通过 options.onError(error) 回调返回(error.message 中会包含错误码信息,例如 HansSpeechError(9010002): ...

TTS 引擎检测与设置(Android 优化)

针对国内部分定制 ROM 可能缺失默认引擎或语音包的问题,提供以下辅助 API:

// 检查是否有可用引擎
const available = await isEngineAvailableAsync()

// 获取已安装引擎列表
const engines = await getEnginesAsync()

// 打开系统 TTS 设置页(引导用户安装或切换引擎)
openTtsSettings()

说明:iOS 与 Harmony 使用系统内置唯一引擎,getEnginesAsync() 返回固定的系统引擎信息、isEngineAvailableAsync() 返回 true

离线合成到文件

const filePath = await synthesizeToFileAsync('需要转成音频的文本', {
  language: 'zh-CN',
  // targetFilePath: '/path/to/output.pcm', // 不传则写入应用缓存目录
})
  • Android / iOS 输出 .wav,Harmony 输出 .pcm;不传 targetFilePath 时写入应用缓存目录并返回完整路径
  • iOS 支持并发提交,文件请求按顺序合成,与朗读使用独立队列;WAV 写入并关闭后返回路径,默认路径每个任务独立。写入失败或 stop() 取消当前及排队文件时,Promise 以 9010005 拒绝;取消后可继续提交新任务,已创建的未完成文件会删除。并发时若自行指定 targetFilePath,请为每个任务使用不同路径。
  • Android 的 volume 会应用到合成后的 WAV 数据,0 输出静音,0.5 将采样幅度减半;Promise 在音量处理完成后返回,写入或处理失败时拒绝并返回 9010005。传统 uni-app 的错误回传适配需使用 HBuilderX 5.24 或更新版本。
  • Harmony 的文件合成与朗读共用提交队列,合成 Promise 在文件写入完成后返回;stop() 会取消当前及排队任务。暂停朗读不会中断正在写入的文件,但后续排队任务需在 resume() 后继续。

文本长度限制

  • maxSpeechInputLength: number:Android 为系统限制;iOS 为 Number.MAX_VALUE;Harmony 为 10000
  • getMaxSpeechInputLength(): number:获取当前限制值(用于兼容少量场景下导入常量失败的问题)

平台差异

  • pause()/resume():iOS 为系统原生暂停/恢复;Android 从引擎最后上报的边界恢复,未上报边界时从当前分段开头重播,暂停期间新增朗读继续排队;Harmony 恢复时从暂停的分句开头重新播报(CoreSpeechKit 无暂停/恢复 API)
  • onBoundary:Android 仅 API 26+ 触发;iOS 正常触发;Harmony 暂不支持
  • 超长文本自动分块(autoChunk)三端均支持,由插件内部分句后依次播报

日志

插件内部默认会打印关键行为与事件,可按需关闭:

setLogEnabled(false)
const enabled = isLogEnabled()

错误码

统一错误码段:90xxxxx

  • 9010001:not supported(保留码,当前版本未使用)
  • 9010002:input too long(Android)
  • 9010003:invalid voice(iOS)
  • 9010004:get voices failed
  • 9010005:unknown

提示:

  • pause()/resume()/stop()/getAvailableVoicesAsync() 通过 Promise reject 返回错误对象(通常包含 errCode/errMsg/errSubject
  • speak() 的错误通过 options.onError(error) 回调返回

隐私、权限声明

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

无需额外权限

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

不收集任何数据

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

暂无用户评论。