Skip to content

fix(reminder): 高强度提醒改走设备本地 TTS,替换原系统 TTS 通道 #359

Description

@LUPENGHAN

背景

#344 引入的「响铃时用系统 TTS 播报日程」在真机后台场景不可靠,三个根因:

  1. 绑定时机AlarmSoundService 第一次启动往往发生在 App 已在后台、被系统认为受限时,此时 new TextToSpeech() 内部要跨进程绑定 TTS 引擎所在的另一个 App,MIUI 类 ROM 会拦后台进程新发起的这类绑定 → status=-1 稳定失败——即使设备装了引擎、前台手动试听正常。
  2. 包可见性:targetSdk 30+ 不声明 <queries> 的 TTS_SERVICE intent,new TextToSpeech() 查到空引擎列表,初始化稳定失败(真机 adb logcat 实测确认,官方文档明确要求声明)。
  3. 文案生成横跨两端:原生 ReminderSpeechFormatter.java + JS reminderSpeech.ts 两条路径分开维护,且文案不区分提醒强度。

方案

  • 新增全局单例 AlarmTtsEngine.kt:TextToSpeech 改为全模块共用单例,在 AlarmModule 构造时(React Native 加载原生模块,几乎总是应用正常启动的前台时机)抢先绑定一次;响铃时 AlarmSoundService 直接复用这条已建立的连接,绕开「后台新绑定被拦」。
  • AndroidManifest.xml 声明 <queries><intent action="android.intent.action.TTS_SERVICE"/></queries>,解决包可见性。
  • AlarmSoundService 全文案朗读:high 档位且有非空文案时设备 TTS 循环播报(onDone 后延迟重播);引擎未就绪先响打包铃保底、notifyWhenReady() 就绪那一刻无缝切到 TTS;onError/不可用一律回退打包铃。best-effort,绝不因 TTS 崩溃。
  • 文案生成统一收敛到 JS 侧 strengthDelivery.ts::composeReminderSpeech()(删除 reminderSpeech.ts 及其测试):仅 high 强度返回非空;「标题,时间到了。现在已经X点Y分了。」/ 全天「X月X日,今天任务是标题。」/ 读不出时间「标题,时间到了,请及时处理。」;原生只念 JS 传进来的文案。
  • speech_text 全链路打通:AlarmSchedulerPort/NativeAlarmScheduler/TimeflowAlarmBridgeEXTRA_SPEECH_TEXTpresentNow/schedule;删除原生 ReminderSpeechFormatter.java 及其测试。
  • 删除 withTimeflowAlarm.js 配置插件(权限改由 Android library manifest 合并);ExpoLocationMonitor 监听回调 async 化。

验收标准

  • 真机 high 强度响铃时,设备 TTS 实际念出日程标题与时间(而非只有打包铃)。
  • TTS 引擎不可用/语言缺数据/冷启动绑定被拦时回退打包铃,不崩溃不卡死。
  • low/medium 强度不触发 TTS。
  • 无标题、读不出时间、超长文本等边界文案符合规范,空文案一律回退打包铃。
  • 现有 JS/原生单测全部通过。

不做

规格:MiniSpec

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions