欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
本文基于flutter3.27.5开发
一、flutter_tts 库概述
文字转语音(Text-to-Speech,TTS)是移动应用无障碍访问和语音交互的重要功能。在导航应用、有声读物、语音播报、无障碍辅助等场景中,TTS 技术发挥着关键作用。在 Flutter for OpenHarmony 应用开发中,flutter_tts 是一个功能丰富的跨平台文字转语音插件,提供了完整的语音合成能力。
flutter_tts 库特点
flutter_tts 库基于各平台原生 TTS 引擎实现,提供了以下核心特性:
多平台支持:支持 Android、iOS、macOS、Windows、Web、OpenHarmony 六大平台。
语音控制:支持设置语速、音量、音调等参数,灵活控制语音输出效果。
队列模式:支持排队播放和抢占播放两种模式,满足不同业务场景。
回调监听:提供开始、完成、暂停、继续、取消、错误等完整的回调机制。
离线支持:OpenHarmony 平台支持离线语音合成,无需网络连接。
功能支持对比
| 功能 | Android | iOS | OpenHarmony |
|---|---|---|---|
| 语音播放 | ✅ | ✅ | ✅ |
| 停止播放 | ✅ | ✅ | ✅ |
| 暂停播放 | ✅ | ✅ | ✅ |
| 设置语速 | ✅ | ✅ | ✅ |
| 设置音量 | ✅ | ✅ | ✅ |
| 设置音调 | ✅ | ✅ | ✅ |
| 队列模式 | ✅ | ❌ | ✅ |
| 获取语音列表 | ✅ | ✅ | ✅ |
| 离线合成 | ✅ | ✅ | ✅ |
使用场景:语音导航、有声读物、无障碍辅助、智能客服、语音播报、语言学习应用等。
二、安装与配置
2.1 添加依赖
在项目的 pubspec.yaml 文件中添加 flutter_tts 依赖:
yaml
dependencies:
flutter_tts:
git:
url: https://github.com/banlang222/flutter_tts
然后执行以下命令获取依赖:
bash
flutter pub get
2.2 权限配置
flutter_tts 在 OpenHarmony 平台上无需额外权限配置,可以直接使用。
说明:OpenHarmony 的 TTS 功能使用系统内置的语音合成引擎,无需申请特殊权限。
三、API 详解
3.1 FlutterTts 类
FlutterTts 是插件的主类,提供所有文字转语音相关功能。
dart
class FlutterTts {
static const MethodChannel _channel = MethodChannel('flutter_tts');
VoidCallback? startHandler;
VoidCallback? completionHandler;
VoidCallback? pauseHandler;
VoidCallback? continueHandler;
VoidCallback? cancelHandler;
ProgressHandler? progressHandler;
ErrorHandler? errorHandler;
}
3.2 speak 方法
播放指定的文本内容。
dart
Future<dynamic> speak(String text)
参数说明:
text:要播放的文本内容
返回值:
- 返回
1表示播放成功 - 返回
0表示播放失败(如队列模式下正在播放)
使用示例:
dart
final flutterTts = FlutterTts();
await flutterTts.speak('你好,欢迎使用文字转语音功能');
3.3 stop 方法
停止当前的语音播放。
dart
Future<dynamic> stop()
返回值:
- 返回
1表示停止成功
使用示例:
dart
await flutterTts.stop();
3.4 pause 方法
暂停当前的语音播放。
dart
Future<dynamic> pause()
返回值:
- 返回
1表示暂停成功
使用示例:
dart
await flutterTts.pause();
3.5 setSpeechRate 方法
设置语音播放速度。
dart
Future<dynamic> setSpeechRate(double rate)
参数说明:
rate:语速值,范围 0.0 ~ 1.00.0:最慢0.5:正常速度1.0:最快
OpenHarmony 特殊说明:
- OpenHarmony 内部将值映射到 0.5 ~ 2.0 范围
- 实际语速 = rate × 2
使用示例:
dart
await flutterTts.setSpeechRate(0.5);
3.6 setVolume 方法
设置语音播放音量。
dart
Future<dynamic> setVolume(double volume)
参数说明:
volume:音量值,范围 0.0 ~ 1.00.0:静音1.0:最大音量
OpenHarmony 特殊说明:
- OpenHarmony 内部将值映射到 0.0 ~ 2.0 范围
- 实际音量 = volume × 2
使用示例:
dart
await flutterTts.setVolume(0.8);
3.7 setPitch 方法
设置语音音调。
dart
Future<dynamic> setPitch(double pitch)
参数说明:
pitch:音调值,范围 0.5 ~ 2.00.5:最低音调1.0:正常音调2.0:最高音调
使用示例:
dart
await flutterTts.setPitch(1.0);
3.8 setQueueMode 方法
设置队列模式,控制多个语音播放请求的处理方式。
dart
Future<dynamic> setQueueMode(int mode)
参数说明:
mode:队列模式0:排队模式(默认)- 新请求排队等待,当前播放完成后播放下一个1:抢占模式 - 新请求立即打断当前播放
使用示例:
dart
await flutterTts.setQueueMode(1);
3.9 awaitSpeakCompletion 方法
设置是否等待播放完成。
dart
Future<dynamic> awaitSpeakCompletion(bool awaitCompletion)
参数说明:
awaitCompletion:true:speak方法会等待播放完成后返回false:speak方法立即返回(默认)
使用示例:
dart
await flutterTts.awaitSpeakCompletion(true);
await flutterTts.speak('这段文字播放完成后才会继续执行');
print('播放完成');
3.10 getMaxSpeechInputLength 方法
获取最大语音输入长度。
dart
Future<int?> get getMaxSpeechInputLength
返回值:
- OpenHarmony 返回
10000个字符
使用示例:
dart
final maxLength = await flutterTts.getMaxSpeechInputLength;
print('最大输入长度: $maxLength');
3.11 回调监听
flutter_tts 提供完整的回调监听机制:
dart
final flutterTts = FlutterTts();
flutterTts.setStartHandler(() {
print('开始播放');
});
flutterTts.setCompletionHandler(() {
print('播放完成');
});
flutterTts.setCancelHandler(() {
print('播放取消');
});
flutterTts.setPauseHandler(() {
print('播放暂停');
});
flutterTts.setContinueHandler(() {
print('播放继续');
});
flutterTts.setErrorHandler((msg) {
print('播放错误: $msg');
});
四、底层实现原理
4.1 Flutter 端实现
Flutter 端通过 MethodChannel 与原生层通信:
dart
class FlutterTts {
static const MethodChannel _channel = MethodChannel('flutter_tts');
Future<dynamic> speak(String text) async {
return await _channel.invokeMethod('speak', text);
}
Future<dynamic> stop() async {
return await _channel.invokeMethod('stop');
}
Future<dynamic> setSpeechRate(double rate) async {
return await _channel.invokeMethod('setSpeechRate', rate);
}
}
4.2 OpenHarmony 原生实现
原生层使用 OpenHarmony 的 @kit.CoreSpeechKit 模块实现语音合成:
typescript
import { textToSpeech } from '@kit.CoreSpeechKit';
export default class FlutterTtsPlugin implements FlutterPlugin, MethodCallHandler {
private ttsEngine: textToSpeech.TextToSpeechEngine | null = null;
private engineParams: textToSpeech.CreateEngineParams = {
language: 'zh-CN', // 当前仅支持 zh-CN
person: 0, // 音色,当前仅支持 0=聆小珊
online: 1, // 当前仅支持 1=离线
extraParams: {
"style": 'interaction-broadcast',
"locate": "CN",
"name": "EngineName"
}
};
private speakExtraParams: Record<string, Object> = {
"speed": 1, // 语速 0.5-2
"volume": 1, // 音量 0-2
"pitch": 1, // 音调 0.5-2
"languageContext": "zh-CN",
"audioType": "pcm",
"playType": 1, // 1=合成与播报
"soundChannel": 3, // 3=语音播报
"queueMode": 0 // 0=排队 1=抢占
};
onAttachedToEngine(binding: FlutterPluginBinding): void {
textToSpeech.createEngine(this.engineParams, (err, engine) => {
if (!err) {
this.ttsEngine = engine;
this.ttsEngine.setListener(this.speakListener);
}
});
}
speak(text: string): void {
let speakParams: textToSpeech.SpeakParams = {
requestId: this.randomId(),
extraParams: this.speakExtraParams
};
this.ttsEngine?.speak(text, speakParams);
}
}
4.3 核心 API:TextToSpeechEngine
OpenHarmony 提供的 TextToSpeechEngine 是实现语音合成的核心:
创建引擎:
typescript
textToSpeech.createEngine(params, callback)
播放语音:
typescript
engine.speak(text, params)
停止播放:
typescript
engine.stop()
设置监听器:
typescript
engine.setListener({
onStart: (requestId, response) => { },
onComplete: (requestId, response) => { },
onStop: (requestId, response) => { },
onError: (requestId, errorCode, errorMessage) => { }
})
4.4 OpenHarmony 平台限制
当前 OpenHarmony TTS 引擎有以下限制:
| 参数 | 限制 |
|---|---|
| 语言 | 仅支持 zh-CN(中文) |
| 音色 | 仅支持 0(聆小珊) |
| 模式 | 仅支持离线模式(online: 1) |
| 风格 | 仅支持 interaction-broadcast |
五、最佳实践
5.1 初始化 TTS
建议在应用启动时初始化 TTS:
dart
class TtsService {
static final TtsService _instance = TtsService._internal();
factory TtsService() => _instance;
TtsService._internal();
final FlutterTts _flutterTts = FlutterTts();
bool _isInitialized = false;
Future<void> init() async {
if (_isInitialized) return;
await _flutterTts.awaitSpeakCompletion(true);
await _flutterTts.setSpeechRate(0.5);
await _flutterTts.setVolume(1.0);
await _flutterTts.setPitch(1.0);
_flutterTts.setCompletionHandler(() {
print('TTS: 播放完成');
});
_flutterTts.setErrorHandler((msg) {
print('TTS: 播放错误 - $msg');
});
_isInitialized = true;
}
Future<void> speak(String text) async {
await init();
await _flutterTts.speak(text);
}
Future<void> stop() async {
await _flutterTts.stop();
}
}
5.2 长文本分段播放
对于长文本,建议分段播放以提高响应速度:
dart
Future<void> speakLongText(String text) async {
final sentences = text.split(RegExp(r'。|,|?|!|,|\?|!'));
for (var sentence in sentences) {
if (sentence.trim().isEmpty) continue;
await flutterTts.speak(sentence.trim());
}
}
5.3 播放状态管理
使用状态机管理播放状态:
dart
enum TtsState { playing, stopped, paused }
class TtsManager {
final FlutterTts _flutterTts = FlutterTts();
TtsState _state = TtsState.stopped;
TtsState get state => _state;
Future<void> init() async {
_flutterTts.setStartHandler(() {
_state = TtsState.playing;
});
_flutterTts.setCompletionHandler(() {
_state = TtsState.stopped;
});
_flutterTts.setCancelHandler(() {
_state = TtsState.stopped;
});
_flutterTts.setPauseHandler(() {
_state = TtsState.paused;
});
_flutterTts.setContinueHandler(() {
_state = TtsState.playing;
});
}
}
5.4 抢占模式使用场景
在需要打断当前播放的场景使用抢占模式:
dart
await flutterTts.setQueueMode(1);
await flutterTts.speak('第一条消息');
await flutterTts.speak('第二条消息会打断第一条');
六、注意事项
6.1 语言限制
OpenHarmony 当前仅支持中文(zh-CN),如需其他语言需要等待系统更新。
6.2 文本长度
建议单次播放文本不超过 10000 个字符,超长文本应分段播放。
6.3 资源释放
在页面销毁时停止播放:
dart
@override
void dispose() {
flutterTts.stop();
super.dispose();
}
6.4 离线模式
OpenHarmony TTS 默认使用离线模式,无需网络连接,但音色选择有限。
七、完整代码示例

以下是一个完整的可运行示例,展示了 flutter_tts 库的核心功能:
main.dart
dart
import 'package:flutter/material.dart';
import 'package:flutter_tts/flutter_tts.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter TTS Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.purple),
useMaterial3: true,
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final FlutterTts _flutterTts = FlutterTts();
final TextEditingController _textController = TextEditingController();
double _volume = 0.5;
double _pitch = 1.0;
double _rate = 0.5;
int _queueMode = 0;
TtsState _ttsState = TtsState.stopped;
@override
void initState() {
super.initState();
_initTts();
}
Future<void> _initTts() async {
await _flutterTts.awaitSpeakCompletion(true);
_flutterTts.setStartHandler(() {
setState(() {
_ttsState = TtsState.playing;
});
});
_flutterTts.setCompletionHandler(() {
setState(() {
_ttsState = TtsState.stopped;
});
});
_flutterTts.setCancelHandler(() {
setState(() {
_ttsState = TtsState.stopped;
});
});
_flutterTts.setErrorHandler((msg) {
setState(() {
_ttsState = TtsState.stopped;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('播放错误: $msg')),
);
});
}
Future<void> _speak() async {
if (_textController.text.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('请输入要播放的文本')),
);
return;
}
await _flutterTts.setVolume(_volume);
await _flutterTts.setSpeechRate(_rate);
await _flutterTts.setPitch(_pitch);
await _flutterTts.setQueueMode(_queueMode);
await _flutterTts.speak(_textController.text);
}
Future<void> _stop() async {
await _flutterTts.stop();
}
@override
void dispose() {
_flutterTts.stop();
_textController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('文字转语音'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_buildStatusCard(),
const SizedBox(height: 16),
_buildTextInput(),
const SizedBox(height: 16),
_buildControlButtons(),
const SizedBox(height: 24),
_buildSliders(),
const SizedBox(height: 16),
_buildQueueModeSelector(),
],
),
),
);
}
Widget _buildStatusCard() {
Color statusColor;
String statusText;
IconData statusIcon;
switch (_ttsState) {
case TtsState.playing:
statusColor = Colors.green;
statusText = '正在播放';
statusIcon = Icons.volume_up;
break;
case TtsState.stopped:
statusColor = Colors.grey;
statusText = '已停止';
statusIcon = Icons.volume_off;
break;
case TtsState.paused:
statusColor = Colors.orange;
statusText = '已暂停';
statusIcon = Icons.pause_circle;
break;
}
return Card(
color: statusColor.withOpacity(0.1),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Icon(statusIcon, color: statusColor, size: 32),
const SizedBox(width: 12),
Text(
statusText,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: statusColor,
),
),
],
),
),
);
}
Widget _buildTextInput() {
return TextField(
controller: _textController,
maxLines: 5,
decoration: InputDecoration(
labelText: '输入要播放的文本',
border: const OutlineInputBorder(),
suffixIcon: IconButton(
icon: const Icon(Icons.clear),
onPressed: () => _textController.clear(),
),
),
);
}
Widget _buildControlButtons() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton.icon(
onPressed: _ttsState == TtsState.playing ? null : _speak,
icon: const Icon(Icons.play_arrow),
label: const Text('播放'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
),
),
ElevatedButton.icon(
onPressed: _ttsState == TtsState.stopped ? null : _stop,
icon: const Icon(Icons.stop),
label: const Text('停止'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
),
),
],
);
}
Widget _buildSliders() {
return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
_buildSlider(
label: '语速',
value: _rate,
min: 0.0,
max: 1.0,
icon: Icons.speed,
onChanged: (value) => setState(() => _rate = value),
),
const Divider(),
_buildSlider(
label: '音量',
value: _volume,
min: 0.0,
max: 1.0,
icon: Icons.volume_up,
onChanged: (value) => setState(() => _volume = value),
),
const Divider(),
_buildSlider(
label: '音调',
value: _pitch,
min: 0.5,
max: 2.0,
icon: Icons.music_note,
onChanged: (value) => setState(() => _pitch = value),
),
],
),
),
);
}
Widget _buildSlider({
required String label,
required double value,
required double min,
required double max,
required IconData icon,
required ValueChanged<double> onChanged,
}) {
return Row(
children: [
Icon(icon, color: Theme.of(context).colorScheme.primary),
const SizedBox(width: 12),
SizedBox(
width: 60,
child: Text(label, style: const TextStyle(fontWeight: FontWeight.bold)),
),
Expanded(
child: Slider(
value: value,
min: min,
max: max,
onChanged: onChanged,
),
),
SizedBox(
width: 50,
child: Text(
value.toStringAsFixed(2),
textAlign: TextAlign.right,
),
),
],
);
}
Widget _buildQueueModeSelector() {
return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'队列模式',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
RadioListTile<int>(
title: const Text('排队模式'),
subtitle: const Text('新请求排队等待当前播放完成'),
value: 0,
groupValue: _queueMode,
onChanged: (value) => setState(() => _queueMode = value!),
),
RadioListTile<int>(
title: const Text('抢占模式'),
subtitle: const Text('新请求立即打断当前播放'),
value: 1,
groupValue: _queueMode,
onChanged: (value) => setState(() => _queueMode = value!),
),
],
),
),
);
}
}
enum TtsState { playing, stopped, paused }
运行此示例后,您将看到一个完整的文字转语音演示界面,可以输入文本、调整参数并播放语音。
八、总结
flutter_tts 是一个功能丰富的跨平台文字转语音插件,为 OpenHarmony 应用提供了完整的语音合成能力。
优点
- 跨平台一致:统一的 API 接口,支持六大平台
- 功能完整:支持语速、音量、音调等参数控制
- 回调完善:提供完整的播放状态监听
- 离线支持:OpenHarmony 支持离线语音合成
适用场景
- 语音导航应用
- 有声读物应用
- 无障碍辅助应用
- 智能客服系统
- 语音播报系统
- 语言学习应用
最佳实践
- 初始化时设置回调监听
- 长文本分段播放
- 使用状态机管理播放状态
- 页面销毁时停止播放
OpenHarmony 限制
- 仅支持中文(zh-CN)
- 仅支持一种音色(聆小珊)
- 仅支持离线模式