Flutter三方库适配OpenHarmony【flutter_speech】— Core Speech Kit 概述
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net终于到了这个系列最核心的技术点——。前面九篇我们做了大量的铺垫工作:搭环境、学原理、分析源码、创建工程、实现接口。所有这些准备,最终都是为了能正确地调用Core Speech Kit来实现语音识别。Core Speech Kit是OpenHarmony提供的AI语音能力套件,包含语音识别(
前言
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
终于到了这个系列最核心的技术点——Core Speech Kit。前面九篇我们做了大量的铺垫工作:搭环境、学原理、分析源码、创建工程、实现接口。所有这些准备,最终都是为了能正确地调用Core Speech Kit来实现语音识别。
Core Speech Kit是OpenHarmony提供的AI语音能力套件,包含语音识别(ASR)和语音合成(TTS)两大功能。flutter_speech用到的是其中的语音识别部分。
坦白说,Core Speech Kit的文档目前还不够完善。我在适配过程中,很多细节都是靠自己试出来的——比如createEngine的参数格式、setListener的回调时序、各种错误码的含义等。今天我把这些摸索出来的经验都整理出来,希望能帮大家少走弯路。
💡 版本说明:本文基于OpenHarmony API 20的Core Speech Kit。不同API版本的接口可能有差异。
一、HarmonyOS Core Speech Kit 功能介绍
1.1 Kit整体架构
Core Speech Kit是HarmonyOS AI能力的一部分,在系统架构中的位置:

图:Core Speech Kit在HarmonyOS系统架构中的位置
┌─────────────────────────────────────────┐
│ 应用层 (Application) │
│ Flutter App → FlutterSpeechPlugin │
├─────────────────────────────────────────┤
│ 框架层 (Framework) │
│ @kit.CoreSpeechKit │
│ ├── speechRecognizer (语音识别) │
│ └── textToSpeech (语音合成) │
├─────────────────────────────────────────┤
│ 系统服务层 (System Service) │
│ AI Engine Service │
│ Audio Service │
├─────────────────────────────────────────┤
│ 硬件层 (Hardware) │
│ 麦克风 / 扬声器 / NPU │
└─────────────────────────────────────────┘
1.2 两大核心能力
| 能力 | 模块 | 功能 | flutter_speech是否使用 |
|---|---|---|---|
| 语音识别 (ASR) | speechRecognizer | 语音转文字 | ✅ 是 |
| 语音合成 (TTS) | textToSpeech | 文字转语音 | ❌ 否 |
flutter_speech只用到了speechRecognizer模块。如果你以后想做TTS功能,可以参考textToSpeech模块的API。
1.3 导入方式
import { speechRecognizer } from '@kit.CoreSpeechKit';
这一行import就把语音识别相关的所有类型都导入了。speechRecognizer是一个命名空间,包含了引擎创建、参数配置、结果类型等所有内容。
📌 注意导入路径:是
@kit.CoreSpeechKit而不是@ohos.ai.speechRecognizer。后者是旧版API的导入方式,在新版SDK中可能已经废弃。
二、speechRecognizer 模块 API 总览
2.1 核心API列表
speechRecognizer模块提供了以下核心API:
| API | 功能 | 返回类型 | flutter_speech中的使用 |
|---|---|---|---|
| createEngine(params) | 创建识别引擎 | Promise<SpeechRecognitionEngine> | activate方法中调用 |
| SpeechRecognitionEngine.setListener(listener) | 设置回调监听器 | void | setupListener方法中调用 |
| SpeechRecognitionEngine.startListening(params) | 开始识别 | void | startListening方法中调用 |
| SpeechRecognitionEngine.finish(sessionId) | 正常停止 | void | stop方法中调用 |
| SpeechRecognitionEngine.cancel(sessionId) | 取消识别 | void | cancel方法中调用 |
| SpeechRecognitionEngine.shutdown() | 关闭引擎 | void | destroyEngine方法中调用 |
2.2 类型定义
// 引擎创建参数
interface CreateEngineParams {
language: string; // 语言代码,如"zh-CN"
online: number; // 1=在线识别,0=离线识别
}
// 音频信息
interface AudioInfo {
audioType: string; // 音频格式,如"pcm"
sampleRate: number; // 采样率,如16000
soundChannel: number; // 声道数,如1
sampleBit: number; // 位深,如16
}
// 启动参数
interface StartParams {
sessionId: string; // 会话ID
audioInfo: AudioInfo; // 音频参数
extraParams: Record<string, Object>; // 扩展参数
}
// 识别结果
interface SpeechRecognitionResult {
result: string; // 识别文本
isLast: boolean; // 是否是最终结果
}
2.3 API调用流程
createEngine(params) // 1. 创建引擎
│
setListener(listener) // 2. 设置监听器
│
startListening(startParams) // 3. 开始识别
│
├── onStart() // 4. 识别开始回调
├── onResult(result) // 5. 识别结果回调(多次)
├── onComplete() // 6. 识别完成回调
│
finish(sessionId) // 7. 停止识别(或cancel取消)
│
shutdown() // 8. 关闭引擎
三、SpeechRecognitionEngine 引擎创建与配置
3.1 createEngine 详解
这是整个语音识别流程的起点:
// flutter_speech中的引擎创建代码
this.asrEngine = await speechRecognizer.createEngine({
language: language, // "zh-CN"
online: 1 // 在线识别
});
createEngine是一个异步方法,返回Promise<SpeechRecognitionEngine>。这和Android的SpeechRecognizer.createSpeechRecognizer()(同步)不同,需要用await等待。
3.2 参数详解
| 参数 | 类型 | 可选值 | 说明 |
|---|---|---|---|
| language | string | “zh-CN” | 识别语言,目前仅支持中文 |
| online | number | 0 或 1 | 0=离线,1=在线。目前建议用1 |
⚠️ language参数格式:Core Speech Kit要求使用BCP 47格式(用连字符),如
zh-CN。而Dart层传过来的是下划线格式zh_CN。所以需要做格式转换。
flutter_speech中的转换逻辑:
private convertLocale(locale: string): string {
return locale.replace('_', '-');
// "zh_CN" → "zh-CN"
// "en_US" → "en-US"
}
3.3 引擎创建失败的处理
createEngine可能因为多种原因失败:
try {
this.asrEngine = await speechRecognizer.createEngine({
language: language,
online: 1
});
console.info(TAG, 'engine created successfully');
} catch (e) {
console.error(TAG, `createEngine failed: ${JSON.stringify(e)}`);
// 可能的失败原因:
// 1. 设备不支持语音识别
// 2. 语言不支持
// 3. 网络不可用(在线模式)
// 4. 系统资源不足
result.error('SPEECH_ACTIVATION_ERROR',
`Failed to create engine: ${JSON.stringify(e)}`, null);
}
| 失败原因 | 错误表现 | 解决方案 |
|---|---|---|
| 设备不支持 | createEngine抛异常 | 先用canIUse检测 |
| 语言不支持 | createEngine抛异常 | 先用isSupportedLocale检查 |
| 网络不可用 | createEngine超时或失败 | 提示用户检查网络 |
| 资源不足 | createEngine抛异常 | 先释放旧引擎再创建 |
3.4 能力检测
在创建引擎之前,应该先检测设备是否支持语音识别:
// 检测设备能力
if (!canIUse('SystemCapability.AI.SpeechRecognizer')) {
result.error('ERROR_NO_SPEECH_RECOGNITION_AVAILABLE',
'Device does not support speech recognition', null);
return;
}
canIUse是OpenHarmony的系统能力检测API,类似Android的PackageManager.hasSystemFeature()。
| 能力标识 | 含义 | 说明 |
|---|---|---|
| SystemCapability.AI.SpeechRecognizer | 语音识别 | 不是所有设备都支持 |
| SystemCapability.AI.TextToSpeech | 语音合成 | flutter_speech不需要 |
四、支持的语言与识别模式
4.1 语言支持现状
这是目前Core Speech Kit最大的限制——只支持中文:
| 语言 | BCP 47代码 | 支持状态 | 说明 |
|---|---|---|---|
| 中文(普通话) | zh-CN | ✅ 支持 | 主要支持的语言 |
| 英文 | en-US | ❌ 不支持 | 未来可能支持 |
| 法文 | fr-FR | ❌ 不支持 | 暂无计划 |
| 俄文 | ru-RU | ❌ 不支持 | 暂无计划 |
| 意大利文 | it-IT | ❌ 不支持 | 暂无计划 |
| 西班牙文 | es-ES | ❌ 不支持 | 暂无计划 |
flutter_speech的语言校验逻辑:
private isSupportedLocale(locale: string): boolean {
return locale.startsWith('zh');
}
如果用户选择了不支持的语言:
if (!this.isSupportedLocale(language)) {
result.error('ERROR_LANGUAGE_NOT_SUPPORTED',
`Language "${locale}" is not supported on HarmonyOS. Only Chinese (zh_CN) is currently supported.`,
null);
return;
}
😅 现实吐槽:原插件支持6种语言,到了OpenHarmony只能用中文。这确实是个遗憾,但也没办法,Core Speech Kit目前就是这个能力。好在中文识别的准确率还不错。
4.2 识别模式
Core Speech Kit支持两种识别模式:
| 模式 | online值 | 特点 | 适用场景 |
|---|---|---|---|
| 在线识别 | 1 | 准确率高,需要网络 | 大多数场景 |
| 离线识别 | 0 | 无需网络,准确率较低 | 无网络环境 |
flutter_speech目前使用在线识别(online: 1):
this.asrEngine = await speechRecognizer.createEngine({
language: language,
online: 1 // 在线模式
});
📌 为什么选在线模式:在线模式的识别准确率明显高于离线模式,而且大多数使用场景都有网络。如果你的应用需要在无网络环境下工作,可以改成
online: 0,但要做好准确率下降的心理准备。
4.3 中英混合识别
虽然Core Speech Kit官方只支持中文,但在实际测试中我发现它对中英混合文本有一定的识别能力:
输入语音:"打开WiFi设置"
识别结果:"打开WiFi设置" ← 英文单词能正确识别
输入语音:"Hello你好"
识别结果:"Hello你好" ← 中英混合也能识别
输入语音:"Please open the door"
识别结果:(识别失败或乱码) ← 纯英文不行
所以实际上Core Speech Kit的能力是:以中文为主,能识别常见的英文单词和缩写,但不支持纯英文输入。
五、在线识别 vs 离线识别的区别与选择
5.1 详细对比
| 对比维度 | 在线识别 (online=1) | 离线识别 (online=0) |
|---|---|---|
| 网络要求 | 需要网络连接 | 不需要 |
| 识别准确率 | 高(95%+) | 中等(80%+) |
| 响应速度 | 取决于网络延迟 | 较快(本地处理) |
| 词汇量 | 大(云端模型) | 有限(本地模型) |
| 隐私性 | 音频上传到云端 | 数据不出设备 |
| 电量消耗 | 较高(网络+计算) | 较低(仅本地计算) |
| 可用性 | 受网络影响 | 始终可用 |
5.2 选择建议
你的应用需要语音识别
│
├── 用户通常有网络?
│ ├── 是 → 使用在线模式 (online=1)
│ └── 否 → 使用离线模式 (online=0)
│
├── 对准确率要求高?
│ ├── 是 → 使用在线模式
│ └── 否 → 离线模式也可以
│
└── 对隐私要求高?
├── 是 → 使用离线模式
└── 否 → 在线模式
5.3 混合策略
一种更优雅的方案是先尝试在线,失败后降级到离线:
// 混合策略示例(flutter_speech当前未实现,仅供参考)
private async createEngineWithFallback(language: string): Promise<void> {
try {
// 先尝试在线模式
this.asrEngine = await speechRecognizer.createEngine({
language: language,
online: 1
});
console.info(TAG, 'Online engine created');
} catch (onlineError) {
console.warn(TAG, `Online engine failed, trying offline: ${onlineError}`);
try {
// 降级到离线模式
this.asrEngine = await speechRecognizer.createEngine({
language: language,
online: 0
});
console.info(TAG, 'Offline engine created (fallback)');
} catch (offlineError) {
console.error(TAG, `Both modes failed: ${offlineError}`);
throw offlineError;
}
}
}
💡 未来改进方向:flutter_speech目前硬编码了
online: 1,如果要支持离线模式,可以通过Dart层的参数传递来控制。这是一个很好的PR贡献方向。
六、Core Speech Kit 与其他平台引擎的对比
6.1 三平台引擎对比
| 对比维度 | Android SpeechRecognizer | iOS SFSpeechRecognizer | OHOS Core Speech Kit |
|---|---|---|---|
| 引擎创建 | 同步 | 同步 | 异步 |
| 语言支持 | 多语言 | 多语言 | 仅中文 |
| 离线支持 | 部分设备 | iOS 13+ | 支持但准确率低 |
| 音频管理 | 系统自动 | 手动(AVAudioEngine) | 系统自动 |
| 回调模式 | RecognitionListener | Block闭包 | setListener |
| 部分结果 | onPartialResults | isFinal=false | isLast=false |
| 置信度 | 有 | 有 | 无 |
| 会话管理 | 隐式 | Task对象 | sessionId |
| VAD控制 | 系统默认 | 系统默认 | 可配置 |
6.2 Core Speech Kit的独特优势
虽然在语言支持上有限制,但Core Speech Kit也有一些独特的优势:
- VAD精细控制:可以配置
vadBegin和vadEnd参数,精确控制语音活动检测的灵敏度 - 音频参数可配:可以指定PCM格式、采样率、声道数等,灵活性更高
- 会话管理:通过
sessionId管理识别会话,便于追踪和调试 - 异步创建:引擎创建是异步的,不会阻塞主线程
6.3 flutter_speech中的参数配置
// 音频参数
const audioParam: speechRecognizer.AudioInfo = {
audioType: 'pcm', // PCM格式
sampleRate: 16000, // 16kHz采样率
soundChannel: 1, // 单声道
sampleBit: 16 // 16位深
};
// 扩展参数
const extraParam: Record<string, Object> = {
"recognitionMode": 0, // 识别模式:0=短语音,1=长语音
"vadBegin": 2000, // VAD开始超时:2秒内没检测到语音就停止
"vadEnd": 3000, // VAD结束超时:3秒静音后认为说话结束
"maxAudioDuration": 60000 // 最大录音时长:60秒
};
| 参数 | 值 | 含义 | 调优建议 |
|---|---|---|---|
| audioType | “pcm” | 音频格式 | 固定用PCM |
| sampleRate | 16000 | 采样率 | 16kHz是语音识别的标准采样率 |
| soundChannel | 1 | 声道数 | 语音识别用单声道就够了 |
| sampleBit | 16 | 位深 | 16bit是标准位深 |
| recognitionMode | 0 | 识别模式 | 0=短语音(适合指令),1=长语音(适合听写) |
| vadBegin | 2000 | VAD开始超时(ms) | 太短容易误触发,太长用户等待久 |
| vadEnd | 3000 | VAD结束超时(ms) | 太短会截断长句,太长等待时间久 |
| maxAudioDuration | 60000 | 最大时长(ms) | 根据业务需求调整 |
🎯 调优经验:
vadBegin设2秒、vadEnd设3秒是我测试下来比较平衡的值。如果你的应用是语音指令类的(短句),可以把vadEnd调小到2秒;如果是听写类的(长句),建议调大到5秒。
七、Core Speech Kit 使用注意事项
7.1 引擎生命周期管理
// ✅ 正确的生命周期管理
// 1. 创建引擎
this.asrEngine = await speechRecognizer.createEngine({...});
// 2. 设置监听器
this.asrEngine.setListener({...});
// 3. 开始识别
this.asrEngine.startListening(params);
// 4. 停止或取消
this.asrEngine.finish(sessionId); // 正常停止
// 或
this.asrEngine.cancel(sessionId); // 取消
// 5. 不再使用时销毁
this.asrEngine.shutdown();
this.asrEngine = null;
// ❌ 常见错误
// 错误1:不设置监听器就开始识别
this.asrEngine.startListening(params); // 没有setListener,收不到结果
// 错误2:不销毁引擎
// 引擎会一直占用系统资源
// 错误3:销毁后继续使用
this.asrEngine.shutdown();
this.asrEngine.startListening(params); // 崩溃!
7.2 并发限制
Core Speech Kit有并发限制——同一时间只能有一个活跃的识别会话:
// ❌ 不能同时进行两个识别
engine1.startListening(params1);
engine2.startListening(params2); // 可能失败
// ✅ 先停止旧的,再开始新的
if (this.isListening) {
this.asrEngine.cancel(this.sessionId);
this.isListening = false;
}
this.asrEngine.startListening(params);
flutter_speech的实现中已经处理了这个问题:
private startListening(result: MethodResult): void {
// ...
if (this.isListening) {
this.asrEngine.cancel(this.sessionId); // 先取消旧的
this.isListening = false;
}
// 再开始新的
this.asrEngine.startListening(recognizerParams);
// ...
}
7.3 错误码参考
| 错误码 | 含义 | 常见原因 | 处理建议 |
|---|---|---|---|
| 0 | 成功 | - | - |
| -1 | 通用错误 | 参数错误或内部异常 | 检查参数 |
| -2 | 网络错误 | 无网络或网络超时 | 提示用户检查网络 |
| -3 | 音频错误 | 麦克风被占用 | 释放麦克风资源 |
| -4 | 引擎错误 | 引擎未初始化 | 重新创建引擎 |
| -5 | 权限错误 | 未授权麦克风 | 重新申请权限 |
7.4 网络依赖
在线识别模式下,Core Speech Kit需要稳定的网络连接:
// 建议在activate时检查网络状态
import { connection } from '@kit.NetworkKit';
private async checkNetwork(): Promise<boolean> {
try {
const netHandle = await connection.getDefaultNet();
const netCapabilities = await connection.getNetCapabilities(netHandle);
return netCapabilities.networkCap.includes(
connection.NetCap.NET_CAPABILITY_INTERNET
);
} catch (e) {
return false;
}
}
八、flutter_speech 中 Core Speech Kit 的完整使用
8.1 完整调用链
把flutter_speech中所有涉及Core Speech Kit的代码串起来:
// 第1步:activate方法中创建引擎
private async activate(locale: string, result: MethodResult): Promise<void> {
// 1.1 权限检查(需要abilityContext)
// 1.2 能力检测(canIUse)
// 1.3 语言校验(isSupportedLocale)
// 1.4 创建引擎
const language = this.convertLocale(locale); // zh_CN → zh-CN
this.asrEngine = await speechRecognizer.createEngine({
language: language,
online: 1
});
// 1.5 设置监听器
this.setupListener();
// 1.6 通知Dart层引擎就绪
this.channel?.invokeMethod('speech.onSpeechAvailability', true);
result.success(true);
}
// 第2步:startListening方法中开始识别
private startListening(result: MethodResult): void {
// 2.1 配置音频参数
const audioParam: speechRecognizer.AudioInfo = {
audioType: 'pcm', sampleRate: 16000, soundChannel: 1, sampleBit: 16
};
// 2.2 配置扩展参数
const extraParam: Record<string, Object> = {
"recognitionMode": 0, "vadBegin": 2000, "vadEnd": 3000, "maxAudioDuration": 60000
};
// 2.3 构建启动参数
const recognizerParams: speechRecognizer.StartParams = {
sessionId: this.sessionId,
audioInfo: audioParam,
extraParams: extraParam
};
// 2.4 开始识别
this.asrEngine.startListening(recognizerParams);
result.success(true);
}
// 第3步:setupListener中处理回调
private setupListener(): void {
this.asrEngine.setListener({
onStart(sessionId, eventMessage) { /* → speech.onRecognitionStarted */ },
onResult(sessionId, result) { /* → speech.onSpeech + speech.onRecognitionComplete */ },
onComplete(sessionId, eventMessage) { /* 识别完成 */ },
onError(sessionId, errorCode, errorMessage) { /* → speech.onError */ }
});
}
// 第4步:stop/cancel/destroy
private stop(result: MethodResult): void {
this.asrEngine.finish(this.sessionId); // 正常停止
}
private cancel(result: MethodResult): void {
this.asrEngine.cancel(this.sessionId); // 取消
}
private destroyEngine(): void {
this.asrEngine.shutdown(); // 销毁引擎
this.asrEngine = null;
}
8.2 数据流向图
用户说话
│
▼
麦克风采集音频 (系统自动)
│
▼
Core Speech Kit 处理
│
├── onStart → channel.invokeMethod('speech.onRecognitionStarted')
│ │
│ ▼
│ Dart: recognitionStartedHandler()
│
├── onResult(isLast=false) → channel.invokeMethod('speech.onSpeech', text)
│ │
│ ▼
│ Dart: recognitionResultHandler(text)
│ UI更新:显示实时识别文本
│
├── onResult(isLast=true) → channel.invokeMethod('speech.onRecognitionComplete', text)
│ │
│ ▼
│ Dart: recognitionCompleteHandler(text)
│ UI更新:显示最终结果,停止动画
│
└── onError → channel.invokeMethod('speech.onError', errorCode)
│
▼
Dart: errorHandler()
重新激活引擎
总结
本文全面介绍了OpenHarmony Core Speech Kit的核心知识:
- Kit架构:Core Speech Kit包含语音识别和语音合成两大能力,flutter_speech使用语音识别部分
- API总览:createEngine → setListener → startListening → finish/cancel → shutdown,流程清晰
- 引擎创建:异步创建,需要指定语言和在线/离线模式
- 语言限制:目前仅支持中文,这是最大的限制
- 在线vs离线:在线准确率高但需要网络,离线无需网络但准确率低
- 参数配置:音频参数和VAD参数可以精细调优
到这里,第1-10篇的核心文章就全部完成了。我们已经覆盖了从项目背景到Core Speech Kit的所有基础知识。从第11篇开始,我们将深入具体的功能实现——权限申请、引擎创建、监听器实现等。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
更多推荐

所有评论(0)