移动浏览器出于节省电量和系统资源的目的,通常会在页面进入后台或者设备锁屏时暂停页面的JavaScript执行和媒体播放,这会导致音频列表播放中断。要实现锁屏后持续播放音频列表,需要结合多个浏览器特性进行适配。

核心实现方案
1. 使用Web Audio API管理音频播放
传统的<audio>标签在后台容易被浏览器限制,使用Web Audio API可以更稳定地控制音频播放,避免被系统自动暂停。以下是基础的音频播放管理代码:
// 音频管理器类
class AudioPlayer {
constructor() {
// 创建音频上下文
this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
this.currentSource = null;
this.playList = [];
this.currentIndex = 0;
this.isPlaying = false;
}
// 加载音频并解码
async loadAudio(url) {
const response = await fetch(url);
const arrayBuffer = await response.arrayBuffer();
return await this.audioContext.decodeAudioData(arrayBuffer);
}
// 播放指定音频
async playAudio(audioBuffer) {
// 如果之前有正在播放的音频,先停止
if (this.currentSource) {
this.currentSource.stop();
}
// 创建音频源
this.currentSource = this.audioContext.createBufferSource();
this.currentSource.buffer = audioBuffer;
// 连接到音频上下文的输出
this.currentSource.connect(this.audioContext.destination);
// 播放结束自动播放下一首
this.currentSource.onended = () => {
this.playNext();
};
this.currentSource.start();
this.isPlaying = true;
}
// 播放列表中的下一首
async playNext() {
if (this.playList.length === 0) return;
this.currentIndex = (this.currentIndex + 1) % this.playList.length;
const nextAudioUrl = this.playList[this.currentIndex];
const audioBuffer = await this.loadAudio(nextAudioUrl);
await this.playAudio(audioBuffer);
}
// 设置播放列表
setPlayList(list) {
this.playList = list;
this.currentIndex = 0;
}
}
// 初始化播放器
const player = new AudioPlayer();
// 设置音频列表
player.setPlayList([
'https://ipipp.com/audio1.mp3',
'https://ipipp.com/audio2.mp3',
'https://ipipp.com/audio3.mp3'
]);
// 开始播放第一首
player.loadAudio(player.playList[0]).then(buffer => {
player.playAudio(buffer);
});
2. 通过Service Worker保持后台运行
Service Worker可以在页面进入后台后继续运行,避免播放逻辑被中断。需要注册Service Worker并在其中处理音频相关的后台任务:
// 主线程注册Service Worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js').then(registration => {
console.log('Service Worker注册成功');
}).catch(err => {
console.log('Service Worker注册失败', err);
});
}
// sw.js 内容
self.addEventListener('install', event => {
self.skipWaiting();
});
self.addEventListener('activate', event => {
event.waitUntil(self.clients.claim());
});
// 监听主线程发来的音频控制消息
self.addEventListener('message', event => {
const { type, data } = event.data;
if (type === 'PLAY_AUDIO') {
// 可以在这里处理后台音频播放的逻辑
console.log('后台收到播放指令', data);
}
});
3. 适配Media Session API
Media Session API可以让网页的音频播放和系统媒体控制中心联动,锁屏后用户可以通过系统控制界面操作播放,同时也能提升后台播放的优先级:
// 设置媒体会话信息
if ('mediaSession' in navigator) {
navigator.mediaSession.metadata = new MediaMetadata({
title: '当前播放音频标题',
artist: '音频作者',
album: '音频专辑',
artwork: [
{ src: 'https://ipipp.com/cover.jpg', sizes: '512x512', type: 'image/jpeg' }
]
});
// 设置媒体控制动作
navigator.mediaSession.setActionHandler('play', () => {
// 恢复播放逻辑
player.audioContext.resume();
});
navigator.mediaSession.setActionHandler('pause', () => {
// 暂停播放逻辑
player.audioContext.suspend();
});
navigator.mediaSession.setActionHandler('nexttrack', () => {
// 播放下一首
player.playNext();
});
navigator.mediaSession.setActionHandler('previoustrack', () => {
// 播放上一首
player.currentIndex = (player.currentIndex - 1 + player.playList.length) % player.playList.length;
player.loadAudio(player.playList[player.currentIndex]).then(buffer => {
player.playAudio(buffer);
});
});
}
注意事项
- 不同移动浏览器的后台限制不同,安卓端的Chrome浏览器对后台音频播放的限制相对宽松,iOS端的Safari浏览器限制更严格,需要多做兼容测试。
- 音频播放需要用户主动交互触发,不能在页面加载后自动播放,否则会被浏览器阻止,可以在用户点击播放按钮后再初始化音频上下文和播放逻辑。
- 如果音频列表较长,建议提前预加载下一首音频,避免切换时出现卡顿。
- 部分系统会在后台运行内存不足时回收Service Worker,需要做好播放状态的持久化,避免状态丢失。
兼容性问题处理
对于不支持Web Audio API或者Media Session API的浏览器,可以降级使用传统的<audio>标签,同时监听页面的visibilitychange事件,在页面进入后台时尝试保持音频播放:
// 降级方案
const audioElement = document.createElement('audio');
audioElement.controls = true;
document.body.appendChild(audioElement);
// 监听页面可见性变化
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
// 页面进入后台,尝试保持音频播放
audioElement.play().catch(err => {
console.log('后台播放失败', err);
});
}
});
Web_Audio_APIService_WorkerMedia_SessionBackground_Audio修改时间:2026-06-13 16:21:20