speechSynthesis 작동이 안됩니다-꼭 답변부탁드립니다

이 글의 성격은 무엇인가요?

질문 / 문제 해결

내용을 설명해주세요

안녕하세요.

Apps in Toss WebView에서 speechSynthesis 테스트를 진행했습니다.

결과는 아래와 같습니다.

window exists: true
speechSynthesis: false

즉 window 객체는 존재하지만 speechSynthesis API 자체가 없는 것으로 확인됩니다.

Chrome 브라우저에서는 정상 동작하지만 Apps in Toss 내에서는 동작하지 않습니다.

현재 Apps in Toss WebView에서 speechSynthesis가 공식적으로 지원되는지 확인 부탁드립니다.

안녕하세요 :slight_smile:
웹 표준 api 사용이 가능합니다.

아래 테스트한 코드 공유드립니다.

import { useCallback, useEffect, useState } from 'react';

export function SpeechSynthesisExample() {
  const [text, setText] = useState('안녕하세요, TTS 테스트입니다.');
  const [status, setStatus] = useState('대기');
  const [voices, setVoices] = useState<SpeechSynthesisVoice[]>([]);

  const isSupported = typeof window !== 'undefined' && 'speechSynthesis' in window;

  const loadVoices = useCallback(() => {
    if (!isSupported) return;
    setVoices(window.speechSynthesis.getVoices());
  }, [isSupported]);

  useEffect(() => {
    if (!isSupported) {
      setStatus('미지원 (speechSynthesis 없음)');
      return;
    }
    loadVoices();
    window.speechSynthesis.addEventListener('voiceschanged', loadVoices);
    return () => {
      window.speechSynthesis.removeEventListener('voiceschanged', loadVoices);
      window.speechSynthesis.cancel();
    };
  }, [isSupported, loadVoices]);

  const handleSpeak = () => {
    if (!isSupported) return;

    window.speechSynthesis.cancel();

    const utterance = new SpeechSynthesisUtterance(text);
    utterance.lang = 'ko-KR';

    const koVoice = voices.find((v) => v.lang.startsWith('ko'));
    if (koVoice) {
      utterance.voice = koVoice;
    }

    utterance.onstart = () => setStatus('재생 중');
    utterance.onend = () => setStatus('완료');
    utterance.onerror = (e) => setStatus(`에러: ${e.error}`);

    window.speechSynthesis.speak(utterance);
  };

  const handleStop = () => {
    if (!isSupported) return;
    window.speechSynthesis.cancel();
    setStatus('중지됨');
  };

  return (
    <div style={{ padding: 16 }}>
      <h2 style={{ fontSize: 16, margin: '0 0 8px' }}>speechSynthesis (TTS)</h2>

      <p style={{ fontSize: 13, color: '#666', margin: '0 0 12px' }}>
        상태: <strong>{status}</strong> · 한국어 voice:{' '}
        {voices.filter((v) => v.lang.startsWith('ko')).length}개
      </p>

      <textarea
        value={text}
        onChange={(e) => setText(e.target.value)}
        rows={2}
        style={{
          width: '100%',
          boxSizing: 'border-box',
          padding: 8,
          fontSize: 13,
          borderRadius: 8,
          border: '1px solid #ddd',
          marginBottom: 8,
        }}
      />

      <div style={{ display: 'flex', gap: 8 }}>
        <button
          type="button"
          onClick={handleSpeak}
          disabled={!isSupported}
          style={{ flex: 2, padding: '10px 0', fontSize: 14, fontWeight: 'bold' }}
        >
          말하기
        </button>
        <button
          type="button"
          onClick={handleStop}
          disabled={!isSupported}
          style={{ flex: 1, padding: '10px 0', fontSize: 13 }}
        >
          중지
        </button>
      </div>
    </div>
  );
}

안녕하세요.

안내주신 대로 확인해보았습니다.

현재 Apps in Toss 테스트 환경에서 아래 코드로 확인 시

‘speechSynthesis’ in window

결과가 false로 확인됩니다.

실제 행보카다의 speak 함수는 아래처럼 구현되어 있으며,

if (typeof window === ‘undefined’ || !(‘speechSynthesis’ in window)) {
return;
}

speechSynthesis 자체가 존재하지 않아 음성 재생 로직까지 진입하지 못하고 있습니다.

디버그 결과:
window exists: true
speechSynthesis: false

speechSynthesis API가 지원된다고 안내해주셨는데,
현재 Apps in Toss WebView에서는 window.speechSynthesis 자체가 노출되지 않고 있습니다.

확인 부탁드립니다.

혹시 사용하신 코드를 공유해주실 수 있을까요 ?

const speak = (text: string, lang: string = ‘en-US’) => {
if (typeof window === ‘undefined’ || !(‘speechSynthesis’ in window)) {
return;
}

const cleaned = text.replace(/~/g, ‘’);

const doSpeak = () => {
const voices = speechSynthesis.getVoices();

const utterance = new SpeechSynthesisUtterance(cleaned);
utterance.lang = lang;
utterance.rate = lang === 'en-US' ? 0.8 : 0.9;

const match =
  voices.find(v => v.lang === lang) ||
  voices.find(v => v.lang.startsWith(lang.split('-')[0]));

if (match) {
  utterance.voice = match;
}

speechSynthesis.speak(utterance);

};

if (speechSynthesis.getVoices().length === 0) {
speechSynthesis.onvoiceschanged = () => {
doSpeak();
};
} else {
doSpeak();
}
};

현재 행보카다에서 사용 중인 TTS 코드입니다.

추가로 Apps in Toss 테스트 환경에서 아래 결과를 확인했습니다.

window exists: true
speechSynthesis: false

즉,
‘speechSynthesis’ in window

결과가 false로 확인되어 현재 speak 함수가 return 처리되고 있습니다.

코드상 문제인지, Apps in Toss WebView 환경 차이인지 확인 부탁드립니다.

android에서 해당 현상 재현되네요 조금 더 확인해보겠습니다!

@sodongzagka 님, 확인해보니 안드로이드는 웹뷰 자체에서 해당 API 지원을 하지 않는 것 같아요 :cry:

참고한 문서 공유드려요.