You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>

关键改动说明

  1. 封装初始化逻辑:把AudioContext和缓冲的创建放到initAudio函数里,方便中断后重新创建
  2. 监听interrupted事件:当系统中断音频上下文时,主动关闭旧实例,避免后续调用时出现状态不一致
  3. 播放前状态检查:每次点击按钮时,先判断上下文是否可用——如果已关闭就重新初始化,如果处于暂停状态就调用resume()(这个调用必须在用户交互回调里,iOS不允许无用户交互的音频激活)

这样修改后,锁屏再解锁点击按钮时,会重新建立有效的音频上下文,并且通过用户交互触发的resume操作符合iOS的安全要求,应该就能正常播放音频了。

内容的提问来源于stack exchange,提问作者user4704976

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 18:07:42