news 2026/7/4 6:13:51

羽毛球工具 App HarmonyOS 6.0 实战(04/10):Core Speech Kit 比分播报

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
羽毛球工具 App HarmonyOS 6.0 实战(04/10):Core Speech Kit 比分播报
系列第 4 篇。本文讲一个比赛现场很实用的增强:用户点 A 队 +1 或 B 队 +1 后,App 自动播报当前比分;如果设备不支持,也不能影响手动计分。

一、真实问题背景

羽毛球双打现场,计分员经常同时要看球、点分、提醒换边、记录最终比分。如果每次都低头看手机,比赛节奏会被打断。比分播报的价值不是“炫技”,而是降低现场操作负担。

项目里的实时计分页已经有手动 +1、撤销、重置、结束比赛等基础操作。TTS 播报作为可选增强出现:用户可以选择“播报开/关”,也可以选择“每分播报”或“仅关键分”。

二、目标与边界

本文只讲当前已落地的比分播报,不把语音识别计分混在一起。目标包括:

1. 创建 Core Speech Kit TTS 引擎。2. 每次比分变化时生成播报文案。3. 支持关键分策略。4. 引擎失败时自动关闭播报,不阻断手动计分。

边界是:当前 TTS 是短文本播报,不做后台长文朗读、不接 AVSession 播控卡片、不承诺所有设备都有离线语音包。语音识别和手表端计分属于后续文章。

三、服务层封装

项目把 TTS 能力封装在common/src/main/ets/service/ScoreSpeechService.ets,页面不直接操作引擎。

import { textToSpeech } from '@kit.CoreSpeechKit'; export class ScoreSpeechService { private static engine: textToSpeech.TextToSpeechEngine | undefined = undefined; private static available: boolean = true; private static async ensureEngine(): Promise<textToSpeech.TextToSpeechEngine | undefined> { const engine = await textToSpeech.createEngine({ language: 'zh-CN', person: 0, online: 1 }); ScoreSpeechService.engine = engine; return engine; } }

这里的online: 1按当前项目规则作为离线模式使用。正式发布前仍要在目标设备上验证语音包、音量、系统版本和失败回调表现。

四、只播最新一条

比赛现场连续加分很快,如果每次都排队播完,会出现“比分已经 8 比 6,语音还在播 5 比 4”的错位。项目的做法是在播报前先尝试停止上一条。

static async speak(text: string): Promise<boolean> { const content = text.trim(); if (content.length === 0 || !ScoreSpeechService.available) { return false; } const engine = await ScoreSpeechService.ensureEngine(); if (engine === undefined) { return false; } engine.stop(); const requestId = `score_tts_${Date.now()}`; engine.speak(content, { requestId }); return true; }

这不是最复杂的媒体队列,但非常适合短比分播报。它优先保证“当前比分正确”,而不是保证每条历史语音都播完。

五、页面侧策略

features/src/main/ets/scoring/LiveScoringPage.ets维护两个状态:speechEnabledspeechCriticalOnly。前者决定是否播报,后者决定每分播还是只播关键分。

@State speechEnabled: boolean = false; @State speechCriticalOnly: boolean = false; speakScoreIfNeeded(matchId: string, previousScoreA: number = -1, previousScoreB: number = -1): void { if (!this.speechEnabled) { return; } if (this.speechCriticalOnly && !this.isCriticalScore(match)) { return; } this.speakText(this.scoreAnnouncement(match)); }

这个状态设计有一个好处:播报只是计分流程的旁路。即使 TTS 失败,比分仍然写入页面状态,比赛仍然可以继续。

六、失败兜底

设备不支持、离线语音包不可用、引擎创建失败,都可能导致播报失败。项目的处理方式是:ScoreSpeechService.speak返回false后,页面关闭播报开关并给出提示。

ScoreSpeechService.speak(text).then((success: boolean) => { if (!success) { this.speechEnabled = false; this.speechRenderTick += 1; Feedback.toast('当前设备暂不可用语音播报'); } });

这条边界非常重要。比赛现场不能因为一个增强能力不可用,就让手动计分崩掉。TTS 是锦上添花,手动计分才是主流程。

七、取舍与风险

当前实现没有做后台播控,也没有做长时间音频任务。原因是比分播报通常是短文本、短时触发,不需要把它包装成完整播放器。后续如果要做“后台长文朗读”或“系统播控卡片”,就应接入 AVSession 和后台音频任务,那是另一类工程。

另一个风险是语音播报与快速点击的竞态。项目通过“播前 stop”降低队列积压,但仍需要真机验证高频点击、切后台、音量为零、语音包缺失等场景。

八、验证命令

构建验证:

& 'D:\HuaweiDevelopFormalStudy\DevEco Studio\tools\hvigor\bin\hvigorw.bat' assembleHap --mode module -p product=default --no-daemon

验证时间:2026-06-28。当前构建结果为BUILD SUCCESSFUL。真机验收建议至少覆盖:开启播报、连续加分、切换关键分、结束比赛播报、禁用语音包时自动关闭。

九、官方参考

Core Speech Kit 相关 API 需要以官方文档为准,可从 HarmonyOS AI / 语音能力文档入口 查询当前 SDK 的@kit.CoreSpeechKit能力和设备限制。

十、工程验收清单

- TTS 封装在common服务层,页面不直接持有复杂引擎逻辑。- 播报开关默认不干扰手动计分。- 快速加分时优先播最新比分。- TTS 失败后关闭播报,不破坏比分记录。- 关键分策略在页面侧控制,便于以后扩展。- 语音识别计分不与本文混淆,后续单独验证。

十一、小结

系统语音能力最适合从“小而稳”的场景切入。比分播报就是这样的切入点:短文本、低权限、失败可兜底、业务价值直接。把这一步做好,再考虑语音计分、手表端计分和多设备同步,工程风险会低很多。

十二、下一篇衔接

下一篇讲分享闭环:如何把费用计算结果截图成图片,写入缓存文件,再通过 ShareKit 分享给其他应用。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 7:22:29

小程序从本地存储迁移到服务端,全程记录,都是干货!!

我的小程序从本地存储迁到服务端&#xff0c;全程记录 几个月前我做了个小程序叫「一纸云深」&#xff0c;一个记录每日心情的情绪治愈工具。一开始图省事&#xff0c;所有数据都存在微信小程序的本地缓存里。 用户用了一段时间后&#xff0c;问题来了&#xff1a; ❌ 换个设…

作者头像 李华
网站建设 2026/7/4 3:47:16

Havenlon 白皮书解读|架构笔记(一):Havenlon 不是钱包

本文解读自《Havenlon Whitepaper v2.0》第 3.3 节 Product Ecosystem。 这一节的核心观点是&#xff1a;Havenlon 并不是一台单一设备&#xff0c;也不是传统意义上的硬件钱包&#xff0c;而是一套围绕“执行控制”构建的分层产品体系。This article is based on Section 3.3,…

作者头像 李华
网站建设 2026/7/3 0:39:22

Python openpyxl 如何删除行和列

在数据处理和分析中&#xff0c;Excel 文件是不可或缺的一部分。Python 的 openpyxl 库提供了强大的功能来操作 Excel 文件&#xff0c;包括读取、写入、修改和格式化数据。然而&#xff0c;很多初学者在使用 openpyxl 时会遇到一个常见的问题&#xff1a;如何删除 Excel 文件中…

作者头像 李华
网站建设 2026/6/30 22:44:09

Kimi LeetCode 3425. 最长特殊路径 Python3实现

以下是 LeetCode 3425. 最长特殊路径 的 Python3 实现。 --- 解题思路 这道题的核心是 DFS 滑动窗口&#xff08;树上的双指针&#xff09;&#xff0c;时间复杂度 O(n)&#xff0c;空间复杂度 O(n)。 关键观察 1. 特殊路径的定义&#xff1a;路径上所有节点的值互不相同…

作者头像 李华