Dante
1
안녕하세요, 앱인토스로 게임을 개발 중인 개발자 단테입니다.
현재 PIXI.js 기반의 웹 게임을 앱인토스 환경에서 서비스하고 있는데, 백그라운드/포그라운드 전환 시 사운드 제어와 관련하여 문의드립니다.
현재 상황:
-
웹 환경에서는 visibilitychange, pageshow/pagehide 이벤트로 백그라운드 전환을 감지하여 사운드를 제어하고 있습니다
-
앱인토스 WebView 환경에서는 다음과 같은 이슈가 발생하고 있습니다:
발생 이슈:
1. Android: 앱이 백그라운드 상태일 때 사운드가 계속 재생되는 문제
2. iOS: 백그라운드 전환 후 미니앱에 재접속하면 사운드가 재생되지 않는 문제
질문:
1. 앱인토스 WebView 환경에서 앱의 백그라운드/포그라운드 전환을 정확하게 감지할 수 있는 이벤트나 API가 있을까요?
2. @apps-in-toss/web-framework에서 제공하는 focus/blur 관련 이벤트 핸들러가 있는지 궁금합니다
3. 혹시 사운드/오디오 제어를 위한 별도의 가이드라인이나 베스트 프랙티스가 있다면 공유 부탁드립니다
현재 저희가 시도해본 방법은:
-
document.visibilitychange 이벤트 리스너
-
window.pageshow/pagehide 이벤트 리스너
-
Web Audio API의 AudioContext 상태 관리
위 방법들이 일반 웹 환경에서는 잘 동작하지만, 앱인토스 WebView에서는 기대한 대로 동작하지 않고 있습니다.
조언 부탁드립니다. 감사합니다!
Dylan
2
안녕하세요. 방금 visibilitychange 이벤트 리스너 테스트시 정상 동작을 확인하였는데요 ..!
따로 web api를 막지 않기 때문에 visibilitychange 이벤트로 감지해주시면될 것 같아요.
아래 샘플 코드 전달드려요 
import { Button, Text } from '@toss-design-system/mobile';
import { useCallback, useEffect, useRef, useState } from 'react';
declare global {
interface Window {
_bgmAudio?: HTMLAudioElement;
}
}
export default function GoogleAdmobRewardedAdPausePlay() {
const [isSoundOn, setIsSoundOn] = useState(false);
const [needManualResume, setNeedManualResume] = useState(false);
const [log, setLog] = useState<string[]>([]);
const audioRef = useRef<HTMLAudioElement | null>(null);
const addLog = (msg: string) => {
setLog((prev) => [...prev, `[${new Date().toLocaleTimeString()}] ${msg}`]);
};
useEffect(() => {
if (!window._bgmAudio) {
const audio = new Audio('/bgm.mp3');
audio.loop = true;
audio.volume = 1;
audio.preload = 'auto';
window._bgmAudio = audio;
addLog('🎧 오디오 초기화 완료');
} else {
addLog('♻️ 기존 오디오 객체 재사용');
}
audioRef.current = window._bgmAudio;
const audio = audioRef.current;
if (audio && !audio.paused) {
setIsSoundOn(true);
}
}, []);
// ✅ 백그라운드/포그라운드 진입 시 BGM 제어
useEffect(() => {
const handleVisibilityChange = () => {
const audio = audioRef.current;
if (!audio) return;
if (document.visibilityState === 'hidden') {
audio.pause();
setIsSoundOn(false);
addLog('🌙 백그라운드 진입 - BGM 정지');
} else if (document.visibilityState === 'visible') {
audio
.play()
.then(() => {
addLog('🌞 포그라운드 복귀 - BGM 자동 재생 성공');
setIsSoundOn(true);
})
.catch((err) => {
addLog(`⚠️ 포그라운드 복귀 재생 실패: ${err.name}`);
setNeedManualResume(true);
});
}
};
document.addEventListener('visibilitychange', handleVisibilityChange);
return () => {
document.removeEventListener('visibilitychange', handleVisibilityChange);
};
}, []);
const toggleSound = () => {
const audio = audioRef.current;
if (!audio) return;
if (isSoundOn) {
audio.pause();
setIsSoundOn(false);
addLog('🔇 사운드 중지');
} else {
audio
.play()
.then(() => {
setIsSoundOn(true);
addLog('🔊 사운드 재생 시작');
})
.catch((err) => {
addLog(`❌ 재생 실패: ${err.name}`);
});
}
};
return (
<div style={{ padding: '2rem' }}>
<p>배경음악 상태: <strong>{isSoundOn ? '재생 중' : '중지됨'}</strong></p>
<Button title="BGM Toggle" onClick={toggleSound}>
{isSoundOn ? '🔇 사운드 끄기' : '🔊 사운드 켜기'}
</Button>
{needManualResume && (
<p style={{ color: 'red', fontWeight: 'bold' }}>
👉 광고 종료나 앱 재진입 후 사운드를 들으려면 화면을 터치하세요.
</p>
)}
<h3>📜 로그</h3>
<pre
style={{
background: '#000',
padding: '1rem',
height: '200px',
overflowY: 'scroll',
fontSize: '12px',
color: '#0f0',
}}
>
{log.slice().reverse().join('\n')}
</pre>
</div>
);
}
1개의 좋아요