华为创新赛获奖复盘:不仅是 TTS,用 HarmonyOS Speech Kit 让你的应用秒变“哄娃神器”
前言:在《智伴》的“古诗词学习”模块中,我们需要一个既能朗读古诗,又带有标准播控面板(播放/暂停/上一首/下一首)的功能。如果从零开发 UI 和后台播放逻辑,不仅成本高,还容易出现音频焦点冲突等问题。HarmonyOS
Speech Kit提供的TextReader(朗读控件) 完美解决了这个问题,它就像是一个系统级的“朗读播放器”,让开发者能以极低的成本集成高质量的朗读功能。
一、 为什么选择 TextReader?
在 HarmonyOS 中,实现“文字转语音”主要有两种方式:
textToSpeech(Core Speech Kit):底层的 TTS 引擎,只负责合成声音,不提供 UI,适合游戏音效、无障碍播报等场景。TextReader(Speech Kit):场景化的朗读控件,自带悬浮播控条,支持后台播放、锁屏控制、播放列表管理。
对于《智伴》的古诗朗读场景,我们需要用户能看到当前读到哪一首,能随时暂停或切换,且在应用切到后台时(比如孩子一边听诗一边玩积木)声音不能断。显然,TextReader 是最佳选择。
二、 实战:打造古诗朗读播放器
我们将结合《智伴》的源码 GushiPage.ets,一步步实现这个功能。
1. 权限配置
TextReader 支持后台朗读,因此需要在 module.json5 中申请长时任务权限,并在代码中配置。
module.json5:
"requestPermissions": [
{
"name": "ohos.permission.KEEP_BACKGROUND_RUNNING"
}
]
2. 初始化 TextReader
在使用朗读功能前,必须先调用 init 方法。建议在页面的 aboutToAppear 生命周期中进行。
import { TextReader } from '@kit.SpeechKit';
import { common } from '@kit.AbilityKit';
@Entry
@Component
struct GushiPage {
private context = getContext(this) as common.UIAbilityContext;
aboutToAppear() {
this.initTextReader();
}
private initTextReader() {
// 初始化参数
let readParams: textReader.ReaderParam = {
isMinibarNeeded: true, // 是否显示悬浮播控条 (类似小艺朗读)
keepBackgroundRunning: true, // 是否允许后台运行
agentName: '智伴', // 播控条上显示的应用名称
agentInfo: {
icon: $r('app.media.logo'), // 播控条上的图标
name: '智伴'
}
};
TextReader.init(this.context, readParams).then(() => {
console.info('TextReader 初始化成功');
}).catch((err: BusinessError) => {
console.error(`TextReader 初始化失败: ${err.code}, ${err.message}`);
});
}
}
3. 构造播放列表并起播
TextReader 接受 ReadInfo 数组作为播放列表。我们需要将数据库中的古诗数据转换为这种格式。
// 定义古诗数据结构
interface Gushi {
id: number;
title: string;
author: string;
content: string;
}
// 播放古诗
private playGushi(gushiList: Gushi[], startIndex: number) {
// 1. 转换为 ReadInfo 数组
let readInfoList: textReader.ReadInfo[] = gushiList.map(item => ({
id: item.id.toString(), // 唯一标识,必须是字符串
title: item.title, // 标题,显示在播控条上
content: item.content, // 朗读的文本内容
author: item.author, // 作者
category: '古诗' // 分类
}));
// 2. 指定起播文章的 ID
let startId = gushiList[startIndex].id.toString();
// 3. 调用 start 方法起播
TextReader.start(readInfoList, startId).then(() => {
console.info('开始朗读');
}).catch((err: BusinessError) => {
console.error(`起播失败: ${err.code}, ${err.message}`);
});
}
代码解析:
readInfoList:整个播放列表。TextReader会自动管理这个列表,用户点击“下一首”时会自动播放列表中的下一项。startId:指定从列表中的哪一项开始播放。
4. 监听播放状态与交互
为了让 App 界面(如播放按钮图标)与 TextReader 的状态保持同步,我们需要监听相关事件。
aboutToAppear() {
// ... 初始化代码 ...
// 监听状态变化
TextReader.on('stateChange', (state: textReader.ReaderState) => {
// state: 1(播放中), 2(暂停), 3(停止)
this.isPlaying = (state === 1);
});
// 监听点击播控条文章标题事件
TextReader.on('clickArticle', (articleId: string) => {
// 用户在播控条点击了某首诗,App 可以跳转到对应的详情页
console.info(`用户点击了文章: ${articleId}`);
});
}
5. 资源释放
当用户退出页面或不再需要朗读时,务必释放资源。
aboutToDisappear() {
// 停止播放并释放资源
TextReader.stop();
TextReader.release();
// 取消所有监听
TextReader.off('stateChange');
TextReader.off('clickArticle');
}
三、 踩坑指南
在开发《智伴》的过程中,我们也遇到了一些“坑”,希望能帮你避开:
- 权限问题:如果在模拟器上运行,可能无法看到悬浮播控条,建议使用真机调试。
- ID 唯一性:
ReadInfo中的id必须在列表中唯一,否则可能会导致播放顺序混乱。 - 内容长度:虽然
TextReader适合长文本,但如果单篇内容过长(如几万字),建议通过RequestMore事件进行分段加载,避免一次性传入导致内存占用过高。
四、 总结
通过 TextReader,《智伴》仅用不到 100 行核心代码,就实现了一个功能完备、体验一致的古诗朗读功能。它不仅节省了开发时间,更重要的是,它利用系统级能力保证了音频播放的稳定性和流畅性。
对于不需要复杂 UI 定制的朗读场景,TextReader 绝对是 HarmonyOS 开发者的首选。
下一篇,我们将深入更底层的 Core Speech Kit,看看如何实现游戏中的实时语音反馈和指令识别。
166



被折叠的 条评论
为什么被折叠?



