MD 阅读 Android 版 · 语音朗读链路验收
逐句朗读、块级浅黄高亮、跟随滚动、从当前可见块起播、语速四档、暂停/继续/停止、时长进度。
版本:1.1.4 (versionCode 1001004) 包名:
com.bzm.mdreader.android验证机:华为 Mate 30 Pro (LIO-AN00) / Android 12 / SDK 31 / 1176×2400 验证日期:2026-09-24 验证方式:USB 真机 + adb 自动化操作 + 日志/音频路由取证
一、结论
语音朗读链路已完整落地并通过真机全量验收,功能与鸿蒙 1.1.4 对齐: 逐句朗读、块级浅黄高亮、跟随滚动、从当前可见块起播、语速四档、暂停/继续/停止、时长进度。
存在 1 项平台差异(非缺陷,见第三节):Android 侧不支持「断点续播」, 暂停后继续会从当前句开头重播。面板提示文案已按引擎能力自动切换,如实告知用户。
二、实现方案
2.1 平台能力差异决定了技术路线
| 能力 | 鸿蒙 CoreSpeechKit | Android TextToSpeech |
|---|---|---|
| 合成方式 | speak(playType:0) 输出 PCM,自持 AudioRenderer 播放 | speak() 边合成边播(流式),无 PCM 出口 |
| 精确暂停 | ✅ AudioRenderer.pause(缓冲冻结、原样续播) | ❌ 无 pause API |
| 逐句推进 | onComplete 回调 | UtteranceProgressListener.onStart / onDone / onError |
| 播放位定位 | 需按已写入 PCM 字节轮测(合成远快于播放) | onStart 本身就是播放位(流式播放) |
因此 Android 侧采用「逐句 speak」:一句一个 utterance,onStart 回调即
「用户正在听的那一句」——直接驱动高亮与跟随滚动,省掉了鸿蒙端那套 PCM 字节轮测。
暂停 = stop() 清队列 + 记住当前句;继续 = 从该句重新 speak。
stop/start/release 均自增会话代号,native 回调先比对代号,杜绝「停止后幽灵出声」。
2.2 改动文件
| 文件 | 说明 |
|---|---|
core/TtsPlayer.kt | 新增。TTS 引擎编排(对应鸿蒙 utils/TtsService.ts) |
ui/ReadCard.kt | 新增。朗读面板 UI(对应鸿蒙 @Builder ReadCard) |
ui/ReaderScreen.kt | 自持 LazyListState、回报可见块、底部面板 slot 分栏 |
MainActivity.kt | 持有 TtsPlayer、绑定回调、引擎预热、面板接线 |
core/ReadScript.kt | 沿用(此前已 1:1 移植,本轮直接复用其块对齐分段) |
三、真机验收清单(全部通过)
| # | 验收项 | 结果 | 证据 |
|---|---|---|---|
| 1 | 引擎初始化 | ✅ | engine=com.huawei.hiai, lang=0(可用), voices=4,耗时 ~350ms |
| 2 | 文本切分 | ✅ | demo.md → 175 句,块号一一对齐 |
| 3 | 音频真实输出 | ✅ | dumpsys audio:AudioTrack state:started, usage=USAGE_MEDIA, content=CONTENT_TYPE_SPEECH, uid=28224(本应用) |
| 4 | 块级浅黄高亮 | ✅ | #FFF7CC,随朗读推进:seg 1→5→6 对应 block 1→2→3 |
| 5 | 跟随滚动 | ✅ | 朗读块自动滚入视口(animateScrollToItem) |
| 6 | 从当前可见块起播 | ✅ | 起播点取 LazyListState.firstVisibleItemIndex,实际从引用块(block 1)开始 |
| 7 | 语速四档 | ✅ | [0.75, 1.0, 1.25, 1.5](严格对齐鸿蒙 speedOptions);播放中自动禁用 |
| 8 | 暂停 | ✅ | 状态转「已暂停」,计时冻结在 00:56(4 秒后仍为 00:56) |
| 9 | 继续 | ✅ | 恢复「正在朗读」,计时 00:56 → 01:01 继续走 |
| 10 | 停止 | ✅ | 回「准备就绪」,高亮清除,按钮复位「开始」 |
| 11 | 时长进度 | ✅ | 00:07 / 11:45(总时长按 4.5 字/秒估算,与鸿蒙同口径) |
| 12 | 面板视觉 | ✅ | 标题/状态+时间/语速/跟随滚动/提示行/三按钮,与鸿蒙 ReadCard 一致 |
平台差异项(需知情)
| 项 | 说明 |
|---|---|
| 断点续播不可用 | 华为 hiAI 引擎未实现 onRangeStart(API 26+ 的字符区间回调),故 continue 从当前句开头重播,而非从暂停字符处续读。实测日志:resume seg=4 from=0 rangeUsable=false。 |
| 应对 | 面板提示文案按引擎能力自动切换:支持则显示「「继续」将从暂停处接着朗读」,不支持则显示「「继续」会从当前句开头重播(当前语音引擎不支持断点续播)」。已如实告知,不误导。 |
四、零权限/零网络合规性(未破坏)
本轮未新增任何权限。朗读使用系统已装语音引擎(华为 hiAI / 讯飞), Manifest 仍为 零 INTERNET,完全离线,符合应用市场「零权限·零网络·零收集」卖点。
五、下一步
- 保存语音 / MP3 导出(面板按钮已占位)
Android 路线:逐句 synthesizeToFile 产出 WAV → 拼接 → LAME NDK 编码 MP3
(注:系统 MediaCodec 只能输出 AAC/M4A,无法直接产 MP3,需引入 LAME)
- 图形全屏查看层(点击图形放大,对应鸿蒙
FullscreenViewer) - 菜单「设置」项、隐藏系统栏
- 长文档性能与内存复核 → Release 签名打包 → 华为 AGC 上架