iOS 15:锁定屏幕数分钟后Safari中Web Audio播放功能失效
解决iOS 15.0.1锁屏解锁后AudioContext无法播放音频的问题
我之前在iOS Safari上遇到过几乎一模一样的问题——锁屏再解锁后,明明AudioContext状态显示为running,但音频就是播不出来。这本质上是iOS的音频会话管理机制导致的:锁屏时系统会强制暂停音频会话,解锁后虽然上下文状态被标记为恢复,但底层的音频资源关联可能已经断裂,而且iOS严格要求音频播放必须由用户主动交互触发,锁屏后这个权限关联会失效。
核心解决方案
我们需要做两件关键的事:
- 监听
interrupted事件,在AudioContext被中断时销毁旧实例,避免后续状态混乱 - 每次用户触发播放时,确保AudioContext处于可用状态(如果需要则重新创建或resume,且必须在用户交互回调内执行)
修改后的示例代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>audio-test</title> </head> <body> <script> let audioContext; let audioBuffer; // 初始化音频上下文和缓冲 function initAudio() { const AudioContextConstructor = window.AudioContext || window.webkitAudioContext; audioContext = new AudioContextConstructor(); // 监听中断事件,销毁旧上下文 audioContext.addEventListener('interrupted', () => { audioContext.close(); }); // 创建白噪音缓冲 const channels = 2; const frameCount = audioContext.sampleRate * 2.0; audioBuffer = audioContext.createBuffer(channels, frameCount, audioContext.sampleRate); for (let channel = 0; channel < channels; channel++) { const nowBuffering = audioBuffer.getChannelData(channel); for (let i = 0; i < frameCount; i++) { nowBuffering[i] = Math.random() * 2 - 1; } } } // 初始化一次 initAudio(); const button = document.createElement('button'); button.textContent = 'Play Audio'; document.body.append(button); button.addEventListener('click', async () => { // 检查上下文状态,如果已关闭则重新初始化 if (!audioContext || audioContext.state === 'closed') { initAudio(); } // 如果上下文处于暂停/中断状态,先resume(必须在用户交互内执行) if (audioContext.state === 'suspended' || audioContext.state === 'interrupted') { await audioContext.resume(); } // 创建并播放源节点 const currentSourceNode = new AudioBufferSourceNode(audioContext, { buffer: audioBuffer, }); currentSourceNode.connect(audioContext.destination); currentSourceNode.start(); }); </script> </body> </html>
关键改动说明
- 封装初始化逻辑:把AudioContext和缓冲的创建放到
initAudio函数里,方便中断后重新创建 - 监听interrupted事件:当系统中断音频上下文时,主动关闭旧实例,避免后续调用时出现状态不一致
- 播放前状态检查:每次点击按钮时,先判断上下文是否可用——如果已关闭就重新初始化,如果处于暂停状态就调用
resume()(这个调用必须在用户交互回调里,iOS不允许无用户交互的音频激活)
这样修改后,锁屏再解锁点击按钮时,会重新建立有效的音频上下文,并且通过用户交互触发的resume操作符合iOS的安全要求,应该就能正常播放音频了。
内容的提问来源于stack exchange,提问作者user4704976
相关产品推荐
相关产品推荐

