HarmonyOS《柚兔学伴》项目实战22-TextReader 朗读与语音交互

22. TextReader 朗读与语音交互

本章导读

语音交互是儿童教育类应用的核心能力之一。「柚兔学伴」中,诗词朗读、汉字发音、提醒音效等场景均通过 HarmonyOS SpeechKit 的 TextReader 与第三方 SXPlayer 两套方案实现。本章将详解它们的集成方式与实战用法。


22.1 TextReader 初始化

TextReader 是 HarmonyOS@kit.SpeechKit提供的系统级朗读控件,使用前必须在 UIAbility 的onCreate生命周期中完成初始化。

// EntryAbility.etsimport{TextReader}from'@kit.SpeechKit';import{BusinessError}from'@ohos.base';exportdefaultclassEntryAbilityextendsUIAbility{asynconCreate(want:Want,launchParam:AbilityConstant.LaunchParam):Promise<void>{if(this.context){constreaderParams:TextReader.ReaderParam={isVoiceBrandVisible:true,businessBrandInfo:{panelName:'小艺朗读',panelIcon:$r('app.media.startIcon')}};awaitTextReader.init(this.context,readerParams).then(()=>{console.info(`TextReader succeeded in initializing.`);}).catch((e:BusinessError)=>{console.error(`TextReader failed to initialize. Code:${e.code}, message:${e.message}`);})}}}

关键参数说明:

参数类型作用
isVoiceBrandVisibleboolean是否在朗读面板显示语音品牌标识
businessBrandInfo.panelNamestring朗读面板标题,如"小艺朗读"
businessBrandInfo.panelIconResource朗读面板图标资源

初始化必须在onCreate中完成,不能延迟到页面加载阶段,否则后续TextReader.start()调用会失败。


22.2 PoemReader 朗读工具类

为方便多处复用,项目将 TextReader 的调用封装为静态工具类PoemReader

// PoemReader.etsimport{TextReader}from"@kit.SpeechKit";import{BusinessError}from"@kit.BasicServicesKit";exportclassPoemReader{staticplay(poem:string,title:string='',author:string='',date?:string){constreadInfoList:TextReader.ReadInfo[]=[{id:'001',title:{text:title,isClickable:true},author:{text:author,isClickable:true},date:{text:date??newDate().toISOString().split('T')[0],isClickable:false},bodyInfo:poem}];conststartParams:TextReader.StartParams={isMinibarHidden:true,callbackParam:'0'};TextReader.start(readInfoList,undefined,startParams).then(()=>{console.info(`TextReader succeeded in starting`);}).catch((e:BusinessError)=>{console.error(`TextReader failed to start. Code:${e.code}, message:${e.message}`);});}}

ReadInfo 数据结构:

interfaceReadInfo{id:string;// 朗读内容唯一标识title:{text:string;isClickable:boolean};// 标题,可点击跳转author:{text:string;isClickable:boolean};// 作者,可点击跳转date:{text:string;isClickable:boolean};// 日期,不可点击bodyInfo:string;// 朗读正文内容}

StartParams 参数:

参数说明
isMinibarHidden是否隐藏迷你朗读条(true 则全屏朗读面板)
callbackParam回调参数,用于标识本次朗读请求

设计要点:isClickable控制朗读面板中对应区域是否可交互。对于诗词场景,标题和作者可点击查看详情,日期设为不可点击。


22.3 三大使用场景

场景一:PoemPage 诗词播读

在诗词详情页,点击"播读"按钮调用朗读:

// PoemPage.ets@BuilderbuildBottom(){Row(){Button('播读').layoutWeight(1).borderRadius(5).linearGradient({angle:90,colors:[[0xFF33FF,0.0],[0x8E44FF,1]]}).onClick(()=>{PoemReader.play(this.poemInfo?.poem??'');})Blank(10)Button('下一首').layoutWeight(1).borderRadius(5).linearGradient({angle:90,colors:[[0x8E44FF,0.0],[0x1C55FF,1]]}).onClick(()=>{this.generatePoem()})}.width('100%').padding(10)}

此处只传入诗词正文,标题、作者使用默认空值。朗读面板会以全屏模式展示。

场景二:StrokeView 汉字发音

在笔画查询页面,点击 Canvas 区域即可听到当前汉字的读音:

// StrokeView.etsCanvas(this.context!!).width(100).height(100).onReady(()=>{this.canvasReady=true;if(!this.isLoading){this.initializeCanvas();this.strokeManager.startAnimation(this.context!!,()=>{this.updateAnimationInfo();});}}).onClick(()=>{PoemReader.play(this.word);})

this.word是单个汉字(如"样"),TextReader 会自动识别并朗读该字的发音,非常适合儿童识字场景。

场景三:TodoView 诗词卡片朗读

在首页待办视图中,点击诗词卡片触发朗读:

// TodoView.etsColumn({space:12}){Text(this.poem).fontFamily('kaiti').fontWeight(FontWeight.Bold).textAlign(TextAlign.Center).lineSpacing(LengthMetrics.fp(18))}.margin({left:12}).justifyContent(FlexAlign.Center).mainCardStyle().onClick(()=>{PoemReader.play(this.poem);})

诗词内容来自每日推荐,用户轻触即可聆听朗读,实现"看诗即听"的沉浸体验。


22.4 SXPlayer 自定义音频播放

对于非朗读类的音频需求(如计时结束提醒音),项目使用@qtfm/smartxplayer模块的 SXPlayer:

初始化与回调

// TodoView.etsimport{AudioEntry,PlayActionCallback,PlayParams,SXPlayer}from'@qtfm/smartxplayer';constcontext:common.UIAbilityContext=GlobalUIAbilityContext.getContext()@Componentexportstruct TodoView{privatecallback:PlayActionCallback={onPlayPrevious:()=>{},onPlayNext:()=>{},onToggleFavorite:(assetId)=>{}}privatesxplayer:SXPlayer=newSXPlayer(context,{enableLog:true,bundleName:"com.youtoo.study.partner",abilityName:"EntryAbility",playActionCallback:this.callback})}

播放提醒音

倒计时结束时,读取 rawfile 中的铃声文件并播放:

onTimerFinished=async()=>{this.alarmVisible=trueletfileDescriptor=awaitcontext.resourceManager.getRawFd("ringtone_youtoo.mp3");letentity:AudioEntry={fd:fileDescriptor}letparams:PlayParams={audioEntry:[entity],playWhenPrepared:true,hasPrevious:false,hasNext:false,isLive:false}this.sxplayer!.play(params)}

PlayParams 参数说明:

参数类型说明
audioEntryAudioEntry[]音频数据源,支持 fd 文件描述符
playWhenPreparedboolean准备就绪后自动播放
hasPreviousboolean是否有上一首
hasNextboolean是否有下一首
isLiveboolean是否为直播流

smartxplayer 模块导出

export{SXPlayer,SXWorkerPlayer,SXBaseAudioPlayer,SXCastPlayer,ISXAudioPlayer}
  • SXPlayer:标准播放器,适合短音频播放
  • SXWorkerPlayer:Worker 线程播放器,避免阻塞 UI
  • SXBaseAudioPlayer:基础播放器抽象类
  • SXCastPlayer:投播播放器
  • ISXAudioPlayer:播放器接口定义

22.5 两套方案对比与选型建议

对比维度TextReaderSXPlayer
适用场景文本朗读(诗词、汉字)音频文件播放(铃声、音乐)
输入类型文本字符串文件描述符(fd)
系统依赖SpeechKit第三方模块
朗读面板内置 UI 面板无 UI,纯后台播放
个性化支持品牌信息定制支持播放控制回调

选型原则:

  • 需要系统级朗读 UI + 文本转语音 → TextReader
  • 需要播放预置音频文件 + 自定义控制逻辑 → SXPlayer
  • 两者可共存,互不冲突

本章小结

本章介绍了「柚兔学伴」中语音交互的完整实现方案。TextReader 在 EntryAbility.onCreate 中初始化,通过 PoemReader 工具类在诗词页、笔画页、首页卡片三处统一调用;SXPlayer 则负责计时提醒等纯音频播放场景。两者各司其职,共同构建了应用的语音交互体系。下一章将介绍字帖生成与 PDF 导出功能。