在开放网页上,speechSynthesis 能朗读文字,webkitSpeechRecognition 能把语音转成文字。而在 WebView 里两者都安静下来——但危险之处在于,其中一个还会假装能工作。

Android:speechSynthesis 干脆缺席

Android WebView 从未实现 Web Speech API 的文字转语音部分。speechSynthesis 根本不提供,getVoices() 返回空列表,voiceschanged 事件永不触发。这一点有据可查:ResponsiveVoice 等提供商明确指出原生 TTS"在 Android WebView 中不受支持",页面必须回退到服务端合成 API。用 Cordova 或 Capacitor 打包的混合应用,默认也带着同一道缺口。调用 speechSynthesis.speak() 的页面得到的是沉默,而不是一个可以恢复的错误。

iOS:API 暴露了,却是死的

iOS 是更隐蔽的情况。在 WKWebView 里,webkitSpeechRecognition 存在于 window 上——所以像 if (window.webkitSpeechRecognition) 这样的特性检测会通过——但它实际上从不工作。WebKit 的 Bug 追踪记录把这一点说得很清楚:权限弹窗永不出现,调用返回 service-not-allowed 错误,因为宿主 App 没有声明语音识别的使用描述。页面以为语音输入可用,调用它,然后什么也得不到。WKWebView 里的文字转语音同样不可靠。开发者赖以正确分支的"特性检测",在这里会主动撒谎。

语音失效后,什么会坏

  • 无障碍朗读消失。 依赖页面朗读报价、对账单或预警的视障交易者,得到的是沉默。
  • 语音成交确认可能永不发声。 用 TTS 播报"已下单"的券商,可能静默地没能说出——当用户以为确认已经发生,这是一道危险的缺口。
  • 语音搜索与听写卡住。 车内或车间里的免提输入,永远打不开识别器。
  • 静默,且"假装有支持"。 尤其在 iOS 上,API 看起来存在,于是页面上线了永远不工作的语音 UI。

runtime 解法

宿主自有 runtime 桥接语音层。页面调用 runtime.speak(text, opts) 做朗读、runtime.startDictation() 做语音输入,宿主通过原生引擎解析它们:Android 走 TextToSpeech 与 SpeechRecognizer,iOS 走 AVSpeechSynthesizer 与 SFSpeechRecognizer(并在 App 中声明所需的使用描述)。能力被诚实地查询,嗓音是原生且已安装的,结果可验证。一次集成,覆盖所有引擎,终点是一段真实的声音。

维度WebView宿主自有 runtime
speechSynthesis(TTS)Android WebView 缺失;WKWebView 不可靠原生 TextToSpeech / AVSpeechSynthesizer
webkitSpeechRecognitioniOS WKWebView 暴露却失效(service-not-allowed)原生 SFSpeechRecognizer / Android SpeechRecognizer
特性检测撒谎(API 存在、无弹窗)诚实的能力查询
无障碍朗读静默缺口可靠的朗读
语音成交确认可能永不发声原生、可验证
一致性因引擎而异的陷阱统一

原生 App 能在每台设备上说和听;裸 WebView 在几乎任何设备上都不说,而在 iOS 上还对其它部分撒谎。runtime 给页面一个 speak 调用和一个 dictation 调用——每次调用的终点都是真实的声音。

参考来源