fix(web_order_box): 修复移动端音频和语音播放限制问题
1. 调整响应式布局的最小高度阈值从420px改为300px 2. 添加unlockAudio和unlockSpeech函数,在用户手势上下文解锁浏览器自动播放限制 3. 优化播放逻辑,当音频上下文未解锁时跳过蜂鸣音播放
This commit is contained in:
@@ -406,7 +406,7 @@ input[type='number'] { -moz-appearance: textfield; appearance: textfield; }
|
|||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (orientation: landscape) and (min-height: 420px), (min-width: 900px) {
|
@media (orientation: landscape) and (min-height: 300px), (min-width: 900px) {
|
||||||
.runner-container { padding: 18px 28px; padding-top: calc(12px + env(safe-area-inset-top)); }
|
.runner-container { padding: 18px 28px; padding-top: calc(12px + env(safe-area-inset-top)); }
|
||||||
.runner-header { margin-bottom: 10px; }
|
.runner-header { margin-bottom: 10px; }
|
||||||
.runner-progress { margin-bottom: 12px; }
|
.runner-progress { margin-bottom: 12px; }
|
||||||
|
|||||||
@@ -627,6 +627,9 @@
|
|||||||
updateStaleWarning();
|
updateStaleWarning();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 必须在 await 之前(用户手势上下文中)解锁音频和语音
|
||||||
|
unlockAudio();
|
||||||
|
unlockSpeech();
|
||||||
setButtonLoading(btn, '启动中…');
|
setButtonLoading(btn, '启动中…');
|
||||||
const res = await runTrackedInteraction('启动执行会话', function () {
|
const res = await runTrackedInteraction('启动执行会话', function () {
|
||||||
return apiFetch('POST', '/api/app_order_box/kits/motion_reminder/sessions/start', { card: card });
|
return apiFetch('POST', '/api/app_order_box/kits/motion_reminder/sessions/start', { card: card });
|
||||||
@@ -1061,6 +1064,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openRunner(session, card) {
|
function openRunner(session, card) {
|
||||||
|
unlockAudio(); // 用户手势中解锁音频,确保后续定时器触发的提示音能播放
|
||||||
const steps = (card && Array.isArray(card.steps)) ? card.steps : [];
|
const steps = (card && Array.isArray(card.steps)) ? card.steps : [];
|
||||||
if (!steps.length) {
|
if (!steps.length) {
|
||||||
showAlert('无法启动', '当前卡片没有可执行步骤');
|
showAlert('无法启动', '当前卡片没有可执行步骤');
|
||||||
@@ -1355,6 +1359,17 @@
|
|||||||
} catch (e) { /* 不支持时静默 */ }
|
} catch (e) { /* 不支持时静默 */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 在用户手势中调用,解锁 iOS Safari 的语音合成限制 */
|
||||||
|
function unlockSpeech() {
|
||||||
|
try {
|
||||||
|
if (!('speechSynthesis' in window)) return;
|
||||||
|
const u = new SpeechSynthesisUtterance('');
|
||||||
|
u.volume = 0;
|
||||||
|
window.speechSynthesis.speak(u);
|
||||||
|
window.speechSynthesis.cancel();
|
||||||
|
} catch (e) { /* 静默 */ }
|
||||||
|
}
|
||||||
|
|
||||||
function stopSpeech() {
|
function stopSpeech() {
|
||||||
try {
|
try {
|
||||||
if ('speechSynthesis' in window) window.speechSynthesis.cancel();
|
if ('speechSynthesis' in window) window.speechSynthesis.cancel();
|
||||||
@@ -1384,12 +1399,25 @@
|
|||||||
|
|
||||||
let audioCtx = null;
|
let audioCtx = null;
|
||||||
|
|
||||||
|
/** 在用户手势中调用,解锁 AudioContext(解决浏览器自动播放策略静音问题) */
|
||||||
|
function unlockAudio() {
|
||||||
|
try {
|
||||||
|
const AudioContextCtor = window.AudioContext || window.webkitAudioContext;
|
||||||
|
if (!AudioContextCtor) return;
|
||||||
|
if (!audioCtx) audioCtx = new AudioContextCtor();
|
||||||
|
if (audioCtx.state === 'suspended') {
|
||||||
|
audioCtx.resume().catch(function () {});
|
||||||
|
}
|
||||||
|
} catch (e) { /* 不支持时静默 */ }
|
||||||
|
}
|
||||||
|
|
||||||
function playBeep() {
|
function playBeep() {
|
||||||
try {
|
try {
|
||||||
const AudioContextCtor = window.AudioContext || window.webkitAudioContext;
|
const AudioContextCtor = window.AudioContext || window.webkitAudioContext;
|
||||||
if (!AudioContextCtor) return;
|
if (!AudioContextCtor) return;
|
||||||
if (!audioCtx) audioCtx = new AudioContextCtor();
|
if (!audioCtx) audioCtx = new AudioContextCtor();
|
||||||
if (audioCtx.state === 'suspended') { void audioCtx.resume(); }
|
// 如果仍处于 suspended(无用户手势解锁),跳过本次播放
|
||||||
|
if (audioCtx.state === 'suspended') return;
|
||||||
const osc = audioCtx.createOscillator();
|
const osc = audioCtx.createOscillator();
|
||||||
const gain = audioCtx.createGain();
|
const gain = audioCtx.createGain();
|
||||||
osc.type = 'sine';
|
osc.type = 'sine';
|
||||||
|
|||||||
Reference in New Issue
Block a user