更新记录
1.1.0(2026-09-09) 下载此版本
- 新增引擎/语音自选能力:getEngines() 列出可选项(Android 为已安装 TTS 引擎,iOS 为系统语音),setEngine(id) 一键切换,传 '' 恢复系统默认;朗读中切换自动停止,默认行为不变
- Android:切换引擎走三参构造销毁重建;getEngineName 改用 getCurrentEngine(指定引擎时语义更准)
- iOS:语音列表带名称/语言/音质标注;修复语音标签返回方法源码的问题
- 新增 debug 选项(createSystemTts 第二参,默认关闭),调试日志按需开启;诊断信息仍随 init() 返回值提供
- 文档补齐引擎选择示例、持久化建议与 iOS 保底语音机制说明
1.0.0(2026-09-03) 下载此版本
- 首个版本:Android TextToSpeech / iOS AVSpeechSynthesizer 双端支持(Native.js 纯 JS 实现,免原生插件与自定义基座)
- 朗读控制:播放/暂停/继续/停止;朗读中重复播放自动打断旧朗读
- 参数调节:语速、音高、音量(Android 播放中调参为估算断点续播)
- 失败处理:五类错误码分类上报;Android 引擎缺失一键跳系统 TTS 设置页
- iOS:静音键无声规避、中文语音检测与降级
- Android:引擎包名检测、中文语音数据缺失检测
平台兼容性
uni-app(3.8.3)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| - | - | - | - | √ | - | √ | √ | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
Parrot 学舌鹦鹉 · 系统语音合成(TTS)模块(uni_modules 插件 zqj-parrot-tts)
Parrot = 「鹦鹉学舌」:让 App 复述你给它的文字。取名自 TTS 的本质——你说(写),它学(读)。
适用项目:uni-app 3.x(Vue 3)项目,HBuilderX ≥ 3.6,编译目标为 App(app-android / app-ios)。 环境限制:模块依赖 5+ Runtime(全局对象
plus),只能在 uni-app App 端真机/自定义基座上运行;H5、小程序端会返回降级实现(init()时上报UNSUPPORTED_PLATFORM);纯 Node / 浏览器环境无法运行(没有plus,也没有系统语音引擎),本文示例请在 uni-app App 端执行。 不适用于 uni-app x(uts 项目)。
一、这是什么
一段纯 JS 封装,让你的 App 不写一行原生代码、不装原生插件,就能调用手机系统自带的语音引擎把文字读出来:
| 平台 | 系统能力 | 调用方式 |
|---|---|---|
| Android | android.speech.tts.TextToSpeech |
Native.js(plus.android) |
| iOS | AVFoundation.AVSpeechSynthesizer |
Native.js(plus.ios) |
典型用途:播报通知、朗读文章、无障碍辅助、验证码语音提示等。两端都不需要任何系统权限(TTS 不涉及麦克风),标准基座(HBuilderX 直接「运行到手机」)即可调试。
模块内部已经处理好了这些脏活:
- 平台判断与双端分流(条件编译 +
platform二次判断); - Android 引擎初始化是异步回调、iOS 是同步——统一成
Promise; - Android 部分厂商引擎(如小米)忽略语速/音高参数——提供当前引擎包名查询与「打开系统 TTS 设置」引导;
- Android 没有暂停接口、拿不到播放进度——按「时长 × 语速」估算断点续播;
- iOS 静音键导致无声、部分基座
plus.ios.import()+invoke()链路失效——分别做了规避与双路径调用兜底;中文语音方面,系统在中文环境下会自动下载并保留地区保底语音(zh-CN 通常为「婷婷」,系统组件不可删),所以 iOS 基本零配置开箱即读,模块的缺语音检测仅作兜底。
二、快速开始
引入路径(注意是文件夹 + index):
import { createSystemTts } from '@/uni_modules/zqj-parrot-tts/js_sdk/index'
// 1. 创建实例(一个页面创建一个即可)
const tts = createSystemTts((state, err) => {
// 所有失败都不抛异常,统一从这里拿到原因
if (err) {
// err.code: UNSUPPORTED_PLATFORM / NOT_READY / INIT_FAILED / VOICE_MISSING / PLAY_FAILED
uni.showModal({ title: '语音不可用', content: err.message, showCancel: false })
}
console.log('引擎状态:', state) // init → ready → speaking ⇄ paused;异常为 error
})
// 2. 初始化(进入页面时调用一次;Android 是异步回调,必须 await)
onMounted(async () => {
const pick = await tts.init()
if (!pick.voiceFound) {
// iOS 极罕见:中文环境下系统会自动下载并保留保底语音(婷婷),
// 检测不到时更可能是调用环境问题——看控制台 [tts-ios] 日志定位;
// 手动路径兜底:设置 > 辅助功能 > 朗读内容 > 声音(若手动删过语音包,系统也会自动恢复保底语音)
}
})
// 3. 朗读
function play() {
tts.speak('你好,这是系统语音引擎朗读的文本', {
rate: 1.0, // 语速倍率,1.0 正常(0.5~2)
pitch: 1.0, // 音高,1.0 正常(0.5~2)
volume: 1.0, // 相对媒体音量 0~1,1.0 跟随系统媒体音量
})
}
// 4. 控制
// tts.pause() / tts.resume() / tts.stop()
// 5. 页面卸载时释放(Android 会 shutdown 引擎)
onUnmounted(() => tts.destroy())
核心参数(TtsSpeakOptions):
| 参数 | 类型 | 范围 | 说明 |
|---|---|---|---|
rate |
number | 0.5~2(建议) | 语速倍率,1.0 = 正常。iOS 端内部映射为 AVSpeechUtterance.rate = 0.5 × rate |
pitch |
number,默认 1 | 0.5~2 | 音高。Android setPitch / iOS pitchMultiplier |
volume |
number,默认 1 | 0~1 | 相对媒体音量的缩放。Android 经 KEY_PARAM_VOLUME 播放参数下发;iOS setVolume: |
三个参数都只对下一次 speak() 生效;Android 端播放中调参可改用 changeParamsLive() 立即生效(估算断点续播)。
三、API 参考
createSystemTts(onChange, options?): SystemTts
唯一工厂函数。按运行平台返回对应实现(接口 SystemTts 约束),onChange 在状态变化和错误发生时被调用。所有方法不抛异常,失败一律经 onChange(state, err) 上报。
const tts = createSystemTts(onChange, { debug: false })
options.debug(默认 false):开启后控制台输出调试日志(Android [tts-android] / iOS [tts-ios] 前缀:参数调用、引擎切换、语音枚举等)。排查问题时临时打开即可;iOS 的调用跟踪无论开关都随 init() 返回值(TtsVoicePick.trace)提供。
SystemTts 实例方法
| 方法 | 签名 | 返回 | 说明 |
|---|---|---|---|
init |
(): Promise<TtsVoicePick> |
语音挑选结果 | 初始化引擎,进入 ready。失败时返回值中带诊断信息,同时 onChange 收到 error |
speak |
(text: string, opts: TtsSpeakOptions): void |
— | 朗读。朗读中/暂停中重复调用 = 打断旧朗读、播新的 |
pause |
(): void |
— | 暂停。iOS 真断点;Android 估算位置后停止 |
resume |
(): void |
— | 继续播放 |
changeParamsLive |
(opts: Partial<TtsSpeakOptions>): void |
— | 播放中实时调参,仅 Android 立即生效;iOS 下次播放生效 |
stop |
(): void |
— | 停止并复位进度 |
getState |
(): TtsState |
当前状态 | 'init' \| 'ready' \| 'speaking' \| 'paused' \| 'error' |
getEngineName |
(): string |
引擎包名 | 仅 Android 有值(如 com.google.android.tts);用于排查引擎兼容问题 |
getEngines |
(): Promise<TtsEngineInfo[]> |
可选项列表 | Android:已安装 TTS 引擎(包名+显示名);iOS:系统已安装语音(婷婷/卿萱/en-US…,带语言与音质标注)。需 init 后调用;H5 返回空数组 |
setEngine |
(id: string): Promise<boolean> |
是否成功 | 切换引擎/语音。随时可调(朗读中自动停止);Android 重建引擎实例后回 ready,iOS 即时生效;传 '' 恢复系统默认。失败返回 false(引擎未启用/语音已卸载),不进入 error 态 |
destroy |
(): void |
— | 释放资源,页面 onUnmounted 时调用 |
openSystemTtsSettings |
(): void |
— | 跳系统 TTS 设置页,仅 Android;跳转失败时自动弹手动路径提示 |
另外导出:getTtsPlatform(): TtsPlatform('android' | 'ios' | 'other')与全部类型(SystemTts / TtsState / TtsError / TtsErrorCode / TtsSpeakOptions / TtsVoicePick / TtsStateListener / TtsEngineInfo)。
引擎/语音选择(两端能力对等、语义不同:Android 选「引擎」,iOS 选「语音」):
// 列出可选项:Android = 已安装 TTS 引擎;iOS = 系统已安装语音
const engines = await tts.getEngines()
// engines: [{ id, label, current }, ...]
// 切换到指定项(朗读中自动停止;Android 重建引擎后回 ready,iOS 即时生效)
const ok = await tts.setEngine(engines[1].id)
// 恢复系统默认(Android 默认引擎 / iOS 自动挑选中文语音)
await tts.setEngine('')
持久化由接入方自理(插件不碰存储),示例:
uni.setStorageSync('parrot-engine-id', id) // 保存选择
const saved = uni.getStorageSync('parrot-engine-id') || ''
if (saved) await tts.setEngine(saved) // 下次启动恢复
错误码(TtsError.code)
| code | 含义 | 建议处理 |
|---|---|---|
UNSUPPORTED_PLATFORM |
H5/小程序环境 | 隐藏朗读相关 UI |
NOT_READY |
引擎未就绪(init 未完成或 error 态) | 提示稍候/引导重新初始化 |
INIT_FAILED |
Android 无可用 TTS 引擎 | 调 openSystemTtsSettings() 引导安装 |
VOICE_MISSING |
缺中文语音数据 | Android 跳设置下载语音数据;iOS 引导下载「婷婷」后重新 init() |
PLAY_FAILED |
播放调用失败(含无声诊断信息) | 按 message 提示;iOS 开 debug 看 [tts-ios] 日志,或直接用 init() 返回的 trace |
四、最小可运行示例
⚠️ 运行前提:本模块依赖 uni-app App 端的 5+ Runtime(
plus)与手机系统语音引擎,Node.js / 浏览器 / H5 都跑不起来。下面的页面请放进 uni-app 项目,用 HBuilderX「运行到手机基座」在真机执行(Android 手机开 USB 调试;iOS 需数据线 + 免费 Apple ID 证书,首次启动需在 设置→通用→VPN与设备管理 信任开发者)。
最小完整页面(复制到 pages/test/tts.vue 即可运行):
<template>
<view style="padding: 24rpx">
<input v-model="text" placeholder="输入要朗读的文字" />
<button :disabled="state !== 'ready'" @click="play">播放</button>
<button :disabled="state !== 'speaking'" @click="tts.pause()">暂停</button>
<button :disabled="state !== 'paused'" @click="tts.resume()">继续</button>
<button @click="tts.stop()">停止</button>
</view>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import { createSystemTts, type TtsState } from '@/uni_modules/zqj-parrot-tts/js_sdk/index'
const text = ref('你好,系统语音合成测试')
const state = ref<TtsState>('init')
const tts = createSystemTts((s, err) => {
state.value = s
if (err) uni.showToast({ title: err.message, icon: 'none' })
})
function play() {
tts.speak(text.value, { rate: 1.0, pitch: 1.0, volume: 1.0 })
}
onMounted(async () => {
const pick = await tts.init()
if (!pick.voiceFound) uni.showToast({ title: '未找到中文语音(极罕见),请看控制台 [tts-ios] 日志', icon: 'none' })
})
onUnmounted(() => tts.destroy())
</script>
五、文件结构
uni_modules/zqj-parrot-tts/
├── package.json # 插件描述文件(发布上架用;本地可直接用)
├── readme.md # 本文档
├── changelog.md # 版本日志
├── PUBLISH.md # 发布到 DCloud 插件市场的步骤与前置清单
└── js_sdk/
├── index.ts # 出口:createSystemTts 工厂 + 类型导出 + H5 降级实现
├── types.ts # 全部 TS 类型(SystemTts 接口约束双端实现)
├── platform.ts # getTtsPlatform():条件编译 + platform 二次分流
├── android.ts # Android TextToSpeech 实现
└── ios.ts # iOS AVSpeechSynthesizer 实现(含 Native.js 双路径调用层)
六、常见问题(FAQ)
1. Android 点播放没反应 / 报 INIT_FAILED?
设备没装 TTS 引擎(国行常见)。调 tts.openSystemTtsSettings() 跳过去装「Google 文字转语音」或厂商引擎并下载中文语音数据,回来重新 init()。应用商店找不到引擎时(部分华为/小米机型),可从维护者整理的离线引擎包获取:夸克网盘 https://pan.quark.cn/s/784bcd181ebb(链接失效请在插件市场反馈)。
2. Android 语速/音高拖了没变化?
先看 tts.getEngineName():部分厂商引擎(小米等)会忽略 setSpeechRate/setPitch,属引擎限制。换 Google 文字转语音引擎即可。另外注意 setSpeechRate 只对下一次合成生效——播放中拖动请用 changeParamsLive()(会从估算断点以新参数续播)。
3. Android 暂停后继续,位置差了几秒? Android TTS 没有暂停接口、也拿不到播放进度(进度回调是抽象类,Native.js 代理不了),模块按「时长 × 语速」估算,1~2 秒偏差是预期行为。要精确续播需写原生插件。
4. iOS 没声音?
先了解一个背景:iOS 在中文环境下会自动下载并保留地区保底语音(zh-CN 通常为「婷婷」,系统组件、不可删除,手动删了也会自动恢复;新版系统另有语舒/天逸/美佳等可选项,增强版音质语音才需手动下载)。所以「设备缺中文语音」是极罕见场景,排查顺序:① 媒体音量与静音键(静音键无声问题模块已通过 AVAudioSession playback 类别规避);② 开启 debug 选项看控制台 [tts-ios] 日志(或直接用 init() 返回的 trace)——检测不到语音时更可能是调用环境问题(见 FAQ 6 的基座链路说明);③ 最后才考虑手动路径:设置 → 辅助功能 → 朗读内容 → 声音 → 中文,检查语音列表后回 App 重新 init()。
5. 权限?缓存?跨域?
两端均不需要任何权限声明(不涉及麦克风/网络);无缓存与跨域问题(纯本地系统调用)。唯一资源管理点是页面卸载时调 destroy()。
6. H5 / 小程序能编译通过吗?
能。非 App 端工厂返回降级实现,init() 上报 UNSUPPORTED_PLATFORM,平台实现模块在编译期被条件编译剔除,不会把 plus 打进 H5 包。
7. iOS 免费证书相关? 与本模块无关,但影响调试:免费 Apple ID 签名的基座 7 天过期,到期重新运行即可。
8. 怎么让用户自选引擎/语音?
getEngines() 列出可选项 + setEngine(id) 切换。注意两端语义:Android 选的是「引擎」(Google 文字转语音、讯飞等,可安装多个),iOS 系统只有一个 TTS 引擎、选的是「语音」(婷婷、卿萱、en-US 等)。Android 切换引擎是销毁重建(异步,完成后回 ready),期间朗读自动停止;iOS 即时生效。是否记住选择由你的业务代码决定(插件不管存储)。
发布到 DCloud 插件市场的步骤、package.json 说明与前置清单见 PUBLISH.md。

收藏人数:
下载插件并导入HBuilderX
下载插件ZIP
赞赏(0)
下载 26
赞赏 0
下载 12696233
赞赏 1956
赞赏
京公网安备:11010802035340号