背景介绍

为了完善”智能带办“应用功能,让应用更友好,在带办详情页接入了播报空间,点击后可以播报带办描述和物品列表。入口及交互效果如下:
在这里插入图片描述

播报详情页如下图所示:
在这里插入图片描述

播报能力介绍

朗读控件TextReader是Speech Kit(场景化语音服务)的一项能力,Speech Kit 集成了语音类AI能力,出朗读外包括AI字幕控件(AICaptionComponent)能力,便于用户与设备进行互动,为用户实现朗读文章。
朗读控件应用广泛,例如在用户不方便或者无法查看屏幕文字时,为用户朗读新闻,提供资讯。朗读控件效果如下图所示:
在这里插入图片描述

朗读控件主要接口如下表:

接口名 描述
init(context: common.BaseContext, readParams: ReaderParam): Promise<void> 初始化TextReader。
start(readInfoList: ReadInfo[], articleId?: string): Promise<void> 启动TextReader。
on(type: string, callback: function): void 注册所有事件回调

注意:朗读控件不支持模拟器

播报能力接入
1、初始化

首先需要初始化朗读控件:

async initReader() {  
  if (this.isReaderInit || this.isInitializingReader) {  
    Logger.i(TAG, "initReader bypassed: isReaderInit=" + this.isReaderInit + ", isInitializingReader=" + this.isInitializingReader);  
    return;  
  }  
  this.isInitializingReader = true;  
  Logger.i(TAG, "initReader called");  
  const readerParam: TextReader.ReaderParam = {  
    isVoiceBrandVisible: true,  
    keepBackgroundRunning: true,  
    businessBrandInfo: {  
      panelName: '清单朗读',  
      panelIcon: $r('app.media.startIcon')  
    }  
  }  try {  
    let context: Context | undefined = this.getUIContext()?.getHostContext() ?? getContext(this);  
    Logger.i(TAG, "initReader context available: " + (context !== undefined));  
    if (context) {  
      await TextReader.init(context, readerParam);  
      Logger.i(TAG, "TextReader.init success");  
      this.isReaderInit = true;  
      this.setReaderActionListener();  
    }  
  } catch (err) {  
    const error: Record<string, Object> = err as Record<string, Object>;  
    Logger.e(TAG, `TextReader failed to init. Code: ${error['code']}, message: ${error['message']}`);  
  } finally {  
    this.isInitializingReader = false;  
  }  
}

主要是调用TextReader.init(context, readerParam);,为了避免重复初始化加了状态变量锁。
初始化完成后设置回调监听:

setReaderActionListener() {  
  TextReader.on('stateChange', (state: TextReader.ReadState) => {  
    this.onStateChanged(state);  
  });  
  TextReader.on('requestMore', () => {  
    TextReader.loadMore([], true);  
  })  
}
onStateChanged = (state: TextReader.ReadState) => {  
  if (this.readInfoList.some((info: TextReader.ReadInfo) => info.id === state.id)) {  
    this.readState = state.state;  
  } else {  
    this.readState = ReadStateCode.WAITING;  
  }  
}
2、添加朗读组件

在页面布局中添加朗读组件TextReaderIcon,并且添加点击事件,点击事件中调用TextReader.start开始朗读,方法中填入朗读的文本列表。

Stack() {  
  TextReaderIcon({ readState: this.readState })  
    .width(22)  
    .height(22)  
}  
.width(36)  
.height(36)  
.borderRadius(18)  
.backgroundColor('rgba(255,255,255,0.1)')  
.margin({ right: 12 })  
.onClick(() => {  
  if (!this.isReaderInit) {  
    ToastUtils.showToast(this.getUIContext(), '朗读组件初始化中...')  
    void this.initReader();  
    return  
  }  
  try {  
    void TextReader.start(this.readInfoList, this.readInfoList[0]?.id);  
  } catch (err) {  
    const error: Record<string, Object> = err as Record<string, Object>;  
    Logger.e(TAG, `TextReader failed to start. Code: ${error['code']}, message: ${error['message']}`);  
  }  
})

在调用开始朗读前判断是否初始化朗读控件,如果没有初始化则执行初始化。
readInfoList将带办清单和物品内容文本进行拼接。

3、释放资源

在页面关闭回调中释放资源:

TextReader.stop();  
TextReader.release();  
TextReader.off('stateChange');  
TextReader.off('requestMore');
注意事项

在使用过程中遇到一些坑,这里记录一下。

1、播放时提示未初始化

增加状态变量,如果播放点击时未初始化则重新进行初始化。

2、设置播放按钮颜色

应用主题黑色,按钮也是显示黑色,导致按钮不明显,查看空间属性,没有配置按钮颜色的地方,最后发现是需要设置应用主题色。

  • 如果应用想要跟随系统切换深浅色模式,请将颜色模式设置为COLOR_MODE_NOT_SET。
  • 如果应用想要主动配置颜色模式,请将颜色模式设置为COLOR_MODE_LIGHT(浅色)或者COLOR_MODE_DARK(深色)。

下面以自动跟随系统切换的示例:

onCreate(): void {
  this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
}
3、应用切后台停止播放

若要在后台播放需要配置长时任务,需要在module.json5配置文件中添加ohos.permission.KEEP_BACKGROUND_RUNNING权限,并且加入backgroundModes选项,然后在readerParam中将keepBackgroundRunning配置为true,确保朗读控件后台播报正常。

// module.json5
{
  "module": {
    // ...
    "requestPermissions": [
      {
        "name": "ohos.permission.KEEP_BACKGROUND_RUNNING",
        "usedScene": {
          "abilities": [
            "FormAbility"
          ],
          "when": "inuse"
        }
      },
    ],
    "abilities": [
      {
        // ...
        "backgroundModes": [
          "audioPlayback"
        ],
        // ...
      }
    ]
  }
}

// Index.ets
async init() {
  const readerParam: TextReader.ReaderParam = {
    // ...
    keepBackgroundRunning: true
  }
}
总结

通过在“智能带办”详情页接入 TextReader 朗读控件,本实践完成了从初始化、事件回调、页面集成到资源释放的全链路打通,有效提升了应用的无障碍体验与用户友好性。实践过程系统性地解决了“未初始化”、按钮颜色适配、后台播放等典型问题,并总结出以下关键经验:做好控件状态管理与异常容错、结合主题与颜色模式优化视觉可见性、按需配置权限与后台模式以保证连续播报。这些经验为后续扩展播报内容和打造个性化语音体验打下了坚实基础。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐