浏览器端自动播放限制相关处理

Tags
Video
Web Dev
Published
Mar 26, 2023

简介

浏览器为了防止网页自动播放音视频对用户造成干扰,对音视频的自动播放功能做了限制:在用户与网页产生交互(例如点击、触摸页面等)之前,网页将被禁止播放带有声音的媒体。
本文主要介绍如何解决因自动播放策略限制,导致播放失败的问题。
大部分的浏览器在用户交互之后就放开了 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有自动播放的默认配置白名单,所以类似微信,抖音里面打开自有域名页面是允许自动播放的。
  1. WebView 设置
    1. iOS自动播放配置:
    2. wkwebview mediaPlaybackRequiresUserAction
    3. uiwebview mediaPlaybackRequiresUserAction
    4. IOS10+ mediaTypesRequiringUserActionForPlayback
    5. Android自动播放配置:
    6. setMediaPlaybackRequiresUserGesture
  1. iOS 在低电量模式下,所有系统版本下自动播放均失效,必须用户行为触发才可以播放。

老版本 Safari 同时播放多视频限制

为了改善用户体验,Safari 浏览器加强了对同时播放多个带音频的视频流的限制:当两个视频都不是静音状态时,点击一个视频进行播放后,另外一个视频则会被暂停。
多个视频流中包含音频且未静音则会受到浏览器的该限制,导致只能同时播放一个视频。
iOS 14.0 及以上版本的 Safari 浏览器不存在该限制。

MEI 指数

媒体参与指数 (MEI) 衡量个人在网站上消费媒体的倾向。Chrome 的方法是按来源对重要媒体播放事件的访问量进行比率:
  • 媒体(音频/视频)的使用必须大于 7 秒。
  • 音频必须存在且未静音。
  • 包含视频的选项卡处于活动状态。
  • 视频的大小(以像素为单位)必须大于 200x140。
Chrome 会根据此计算出媒体参与度分数,该分数在定期播放媒体的网站上最高。当它足够高时,媒体只允许在桌面上自动播放。
打开: chrome://media-engagement/
notion image

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);
}

HTMLMediaElement Event

notion image