Media Session API
发布于 更新于
一句话: 根据 MDN 的说明,Media Session API “提供了一种自定义媒体通知的方式”——它让页面 描述当前正在播放的内容,并接收来自设备物理或屏幕媒体控件的事件,与页面自身已有的 播放控件并存。
入口是 navigator.mediaSession,一个 MediaSession 对象。根据 MDN 的
setActionHandler() 参考文档,它的动作“让 Web 应用能够在用户操作设备内置的物理或屏幕
媒体控件(例如播放、停止或快进/快退按钮)时收到通知”;根据 MDN 的 metadata 参考文档,
MediaSession.metadata 持有一个 MediaMetadata 对象,为设备自身的媒体控制界面提供
当前播放内容的描述信息。
根据 MDN 的 browser-compat-data,MediaSession 接口(及其 setActionHandler() 方法)
自 Chrome 73 起受支持,自 Safari 15 起受支持,自 Firefox 82 起受支持。Chrome for
Android 自 57 起支持,但 Firefox for Android 只是部分实现——同一份数据指出 Firefox
for Android “暴露了该 API,但没有提供对应的用户可见媒体控制界面”。该数据将 Android
WebView 记录为不支持(version_added: false)。
设置 metadata 为一个 MediaMetadata 对象,然后为页面能够响应的动作注册处理函数:
const playlist = [ { title: "Unforgettable", artist: "Nat King Cole", album: "The Ultimate Collection (Remastered)" }, { title: "L-O-V-E", artist: "Nat King Cole", album: "The Ultimate Collection (Remastered)" },];let currentTrackIndex = 0;const audioElement = document.querySelector("audio") ?? document.createElement("audio");
function loadTrack(index) { currentTrackIndex = index; const track = playlist[currentTrackIndex]; audioElement.src = `/audio/${track.title}.mp3`; navigator.mediaSession.metadata = new MediaMetadata({ title: track.title, artist: track.artist, album: track.album, artwork: [{ src: "/art/unforgettable-96.png", sizes: "96x96", type: "image/png" }], });}
function playPreviousTrack() { if (currentTrackIndex > 0) { loadTrack(currentTrackIndex - 1); audioElement.play(); }}
function playNextTrack() { if (currentTrackIndex < playlist.length - 1) { loadTrack(currentTrackIndex + 1); audioElement.play(); }}
loadTrack(0);
const actionHandlers = { play: () => audioElement.play(), pause: () => audioElement.pause(), previoustrack: playPreviousTrack, nexttrack: playNextTrack,};
for (const [action, handler] of Object.entries(actionHandlers)) { try { navigator.mediaSession.setActionHandler(action, handler); } catch { // 该浏览器未实现这个媒体会话动作——跳过。 }}根据 MDN 的 setActionHandler() 参考文档,将 null 作为回调传入会移除此前为该动作
设置的处理函数,例如 navigator.mediaSession.setActionHandler("nexttrack", null)。
运行时检测与回退
Section titled “运行时检测与回退”在读写之前先对 navigator 上的 mediaSession 做特性检测,不支持时回退为显示页面自身的
播放/暂停/快进控件,将其作为唯一的控制方式。下面的示例自行创建了这个回退元素
(一个原生的 <audio controls>),因此直接粘贴运行即可生效,而不是假设页面上已经存在
从未添加过的标记:
function supportsMediaSession() { return "mediaSession" in navigator;}
const playerControls = document.querySelector("#player-controls") ?? createPlayerControls();
if (supportsMediaSession()) { navigator.mediaSession.metadata = new MediaMetadata({ title: "Unforgettable" });} else { // 此处不支持 Media Session——依赖页面自身的播放/暂停/快进控件, // 而不是操作系统级别的媒体控件。 showOnPageTransportControls();}
function createPlayerControls() { const audio = document.createElement("audio"); audio.id = "player-controls"; audio.controls = true; audio.src = "/audio/unforgettable.mp3"; audio.hidden = true; document.body.appendChild(audio); return audio;}
function showOnPageTransportControls() { playerControls.hidden = false;}- 根据 MDN 的兼容性数据,Firefox for Android “暴露了该 API,但没有提供对应的用户可见
媒体控制界面”——在该平台上不要因为
setActionHandler()没有抛出异常就假定用户能 实际接触到已设置的处理函数。 - 同一份数据将 Android WebView 记录为不支持——嵌入在 WebView 中的应用仍需要页面自身的 回退控件。
- 根据 MDN 的
setActionHandler()参考文档,各个动作字符串(例如skipad、previousslide、nextslide)的支持情况因浏览器而异,对某浏览器未实现的动作调用 该方法可能会抛出异常——MDN 自己的示例代码将每次setActionHandler()调用都包裹在 独立的try...catch中,避免一个不受支持的动作影响其余设置。 - 根据 MDN 的
metadata参考文档,MediaSession.metadata在页面设置之前为null—— 应做防御性读取,而不要假定MediaMetadata对象已经存在。