On the open web, speechSynthesis reads text aloud and webkitSpeechRecognition turns speech into text. Inside a WebView both go quiet — but the danger is that one of them pretends to work.

Android: speechSynthesis is simply absent

Android WebView never implemented the Web Speech API's text-to-speech side. speechSynthesis is not provided, getVoices() returns an empty list, and the voiceschanged event never fires. This is well documented: providers such as ResponsiveVoice note that the native TTS is "not supported in Android WebView" and the page must fall back to a server-side synthesis API. For a hybrid app built with Cordova or Capacitor, the same gap appears by default. The page that calls speechSynthesis.speak() gets silence, not an error it can recover from.

iOS: the API is exposed but dead

iOS is the more insidious case. In WKWebView, webkitSpeechRecognition is present on window — so a feature check like if (window.webkitSpeechRecognition) passes — but it never actually works. The WebKit bug tracker records this exactly: the permission prompt never appears, and the call returns a service-not-allowed error because the embedding app did not declare the speech-recognition usage description. The page believes voice input is available, calls it, and gets nothing. Text-to-speech in WKWebView is likewise unreliable. Feature detection, the thing developers rely on to branch correctly, actively lies here.

What breaks when voice dies

  • Accessibility read-aloud disappears. Visually impaired traders who rely on the page reading quotes, statements, or alerts aloud get silence.
  • Voice trade confirmation may never speak. A broker that announces "order placed" via TTS can silently fail to say it — a dangerous gap when the user assumes the confirmation happened.
  • Voice search and dictation stall. Hands-free input in a car or on a shop floor never opens the recognizer.
  • Silent, and falsely "supported". Especially on iOS, the API looks present, so the page ships voice UI that never functions.

The runtime fix

A host-owned runtime bridges the speech layer. The page calls runtime.speak(text, opts) for read-aloud and runtime.startDictation() for voice input, and the host resolves them through native engines: Android TextToSpeech and SpeechRecognizer, iOS AVSpeechSynthesizer and SFSpeechRecognizer (with the required usage descriptions declared in the app). Capability is queried honestly, voices are native and installed, and the result is verifiable. One integration, every engine, real audio at the end of it.

DimensionWebViewHost-owned runtime
speechSynthesis (TTS)Missing in Android WebView; unreliable in WKWebViewNative TextToSpeech / AVSpeechSynthesizer
webkitSpeechRecognitionExposed but dead in WKWebView (service-not-allowed)Native SFSpeechRecognizer / Android SpeechRecognizer
Feature detectionLies (API present, no prompt)Honest capability query
Voice for accessibilitySilent gapReliable read-aloud
Voice trade confirmationMay never speakNative, verifiable
ConsistencyPer-engine trapUniform

A native app speaks and listens on every device. A stock WebView speaks on almost none and, on iOS, lies about the rest. A runtime gives the page one speak call and one dictation call — and real audio at the end of each.

Sources