简介
浏览器为了防止网页自动播放音视频对用户造成干扰,对音视频的自动播放功能做了限制:在用户与网页产生交互(例如点击、触摸页面等)之前,网页将被禁止播放带有声音的媒体。
本文主要介绍如何解决因自动播放策略限制,导致播放失败的问题。
大部分的浏览器在用户交互之后就放开了 AutoPlay 限制,该步骤可有效避免出现自动播放失败的错误。但是,由于各浏览器厂商对于自动播放策略的实现存在差异,即使提前引导用户与页面产生交互,也不能确保不会出现自动播放失败错误。因此第二步的处理是必须要保留的。
例如:在微信浏览器及其小程序的 webview 中,必须在用户点击事件的回调函数中调用播放接口,否则播放会失败。倘若在用户点击事件的回调中,使用了 setTimeout 等接口来异步调用播放接口,会出现自动播放失败的错误。
Chrome 自动播放策略:https://developer.chrome.com/blog/autoplay/
Safari 自动播放策略:https://webkit.org/blog/7734/auto-play-policy-changes-for-macos/
Firefox 自动播放策略:https://support.mozilla.org/en-US/kb/block-autoplay
MDN 自动播放指导:https://developer.mozilla.org/zh-CN/docs/Web/Media/Autoplay_guide
自动播放策略
- 音频被静音或其音量设置为 0
- 用户和网页已有交互行为(包括点击、触摸、按下某个键等等)
- 自动播放 权限策略 被应用于
<iframe>
或者其文档上,从而获得了自动播放的权限。
- Chrome 提高MEI指数;如果浏览器确定用户经常与媒体互动,这可能会自动发生,也可能通过首选项或其他用户界面功能手动发生
移动端 WebView
安卓端许多浏览器 WebView 播放视频时,播放器会被系统接管,比如:会有不符合预期的播放器按钮样式。
一些 Native WebView有自动播放的默认配置白名单,所以类似微信,抖音里面打开自有域名页面是允许自动播放的。
- WebView 设置
- iOS 在低电量模式下,所有系统版本下自动播放均失效,必须用户行为触发才可以播放。
老版本 Safari 同时播放多视频限制
为了改善用户体验,Safari 浏览器加强了对同时播放多个带音频的视频流的限制:当两个视频都不是静音状态时,点击一个视频进行播放后,另外一个视频则会被暂停。
多个视频流中包含音频且未静音则会受到浏览器的该限制,导致只能同时播放一个视频。
iOS 14.0 及以上版本的 Safari 浏览器不存在该限制。
MEI 指数
媒体参与指数 (MEI) 衡量个人在网站上消费媒体的倾向。Chrome 的方法是按来源对重要媒体播放事件的访问量进行比率:
- 媒体(音频/视频)的使用必须大于 7 秒。
- 音频必须存在且未静音。
- 包含视频的选项卡处于活动状态。
- 视频的大小(以像素为单位)必须大于 200x140。
Chrome 会根据此计算出媒体参与度分数,该分数在定期播放媒体的网站上最高。当它足够高时,媒体只允许在桌面上自动播放。
打开: chrome://media-engagement/
Chrome 推荐写法
var promise = document.querySelector('video').play();
if (promise !== undefined) {
promise.then(_ => {
// Autoplay started!
}).catch(error => {
// Autoplay was prevented.
// Show a "Play" button so that user can start playback.
});
}
全局监听交互状态写法
也可以监听一下全局状态:
- 页面初始化默认为未自动播放成功
- 监听全局 document.body 的点击事件
- 播放成功后移除监听
- 未成功的情况下如果监听到,即调用 play()
- play 成功之后取消监听事件
- play 失败则不取消监听事件
const handlePlay = () => {
video.play();
}
const body = document.querySelector('body')[0];
body.addEventListener('click', handlePlay); // 移动端的话 click,touch 都可以监听
video.addEventListener('playing', () => {
console.log('自动播放成功');
body.removeEventListener('click', handlePlay);
}