autoplay
背景
原文連結:Chrome 自動播放限制策略
Web 瀏覽器正朝著更嚴格的自動播放策略發展,以改善使用者體驗,降低安裝廣告攔截器的意願,並減少昂貴及/或受限網路上的數據消耗。這些變更旨在為使用者提供更大的播放控制權,並讓開發者獲得合法使用案例。
新的特性
Chrome 的自動播放政策很簡單:
- 靜音自動播放總是允許的。
- 在下列情況下允許使用聲音自動播放:
- 使用者已經與網域進行了互動(點擊、觸碰等)。
- 在桌面上,使用者的媒體參與指數閾值 (MEI) 已被超越,這表示使用者以前播放過帶有聲音的影片。
- 在行動裝置上,使用者已將該網站添加到主畫面。
- 頂層框架可以將自動播放權限授予其 iframe,以允許自動播放聲音。
媒體參與指數 (Media Engagement Index) (MEI)
MEI 衡量個人在網站上消費媒體的傾向。Chrome 目前的方法是訪問每個來源的重要媒體播放事件的比率:
- 媒體消耗(音訊/影片)必須大於 7 秒。
- 音訊必須存在並取消靜音。
- 影片分頁處於活動狀態。
- 影片大小(以像素為單位)必須大於 200x140。
因此,Chrome 會計算媒體參與度分數,該分數在定期播放媒體的網站上最高。當分數足夠高時,媒體播放只允許在桌面上自動播放。MEI 是 Google 自動播放策略的一部分。它是一個演算法,參考了媒體內容的持續時間、瀏覽器分頁是否活動、活動分頁影片的大小這一系列元素。不過也正因此,開發者難以在所有的網頁上都測試這一演算法的效果。
使用者的 MEI 位於 chrome://media-engagement/ 內部頁面

開發者開關
作為開發者,您可能需要在本地變更 Chrome 瀏覽器自動播放政策行為,以根據使用者的參與情況測試您的網站。
- 您可以決定透過將 Chrome 標誌「自動播放策略」設定為「無需使用者手勢」來完全停用自動播放策略 chrome://flags/#autoplay-policy。這樣您就可以測試您的網站,就好像使用者與您的網站保持緊密聯繫一樣,並且始終允許播放自動播放。
- 您也可以決定禁止使用 MEI,以及預設情況下全新 MEI 獲得播放自動播放的網站是否允許新使用者使用,從而決定禁止播放自動播放。這可以用兩個內部開關來完成:chrome.exe --disable-features=PreloadMediaEngagementData, AutoplayIgnoreWebAudio, MediaEngagementBypassAutoplayPolicies
iframe 委託授權
一個功能政策使開發者可以選擇性地啟用和停用各種瀏覽器功能和 API。一旦來源獲得了自動播放權限,它就可以將該權限委託給具有自動播放功能的跨來源 iframe。預設情況下,同源 iframe 可以使用自動播放。
<! - 允许自动播放。- >
<iframe src = "https://cross-origin.com/myvideo.html" allow = "autoplay" />
<! - 允许自动播放和全屏播放。- >
<iframe src = "https://cross-origin.com/myvideo.html" allow = "autoplay; fullscreen" />
當停用自動播放的功能政策時,play() 在不帶使用者手勢的情況下呼叫將拒絕帶有 NotAllowedError DOMException 的 promise。自動播放屬性也將被忽略。
範例場景:
範例 1:每次使用者在他們的筆記型電腦上訪問 iqiyi.com 時,他們都會觀看電視節目或電影。由於其媒體參與度較高,因此可以自動播放。
範例 2:iqiyi.com 同時具有文字和影片內容。大多數使用者偶爾會去該網站獲取文字內容並觀看影片。使用者的媒體參與度較低,因此如果使用者直接從社交媒體頁面或搜尋導航,則不允許自動播放。
範例 3:news.iqiyi.com 同時具有文字和影片內容。大多數人透過主頁進入網站,然後點擊新聞報導。由於使用者與網域互動,新聞文章頁面上的自動播放將被允許。但是,應該注意確保使用者不會對自動播放內容感到意外。
範例 4:在愛奇藝泡泡頁面將 iframe 與電影預告片一起嵌入其評論中。使用者與網域進行互動以訪問特定的網站,因此允許自動播放。但是,泡泡需要將該特權明確委託給 iframe 以便內容自動播放。
Chrome 企業政策
Chrome 企業策略可以改變這種新的自動播放行為,以用於例如資訊站或無人值守系統。查看配置策略和設定說明頁面,了解如何設定這些新的與自動播放相關的企業策略:
- 「AutoplayAllowed」政策控制是否允許自動播放。
- 「AutoplayWhitelist」政策允許您指定 URL 模式的白名單,其中自動播放將始終啟用。
開發人員最佳實踐
影片元素
永遠不要假設影片會播放,並且在影片不是真正播放時不要顯示暫停按鈕。
關注播放函數返回的 Promise
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. }); }使用靜音自動播放
<video id="video" muted autoplay> <button id="unmuteButton"></button> <script> unmuteButton.addEventListener('click', function() { video.muted = false; }); </script>
音訊元素
原生播放音訊除了使用 audio 標籤之外,還有另外一個 API 叫 AudioContext。AudioContext 介面表示由音訊模組連接而成的音訊處理圖,每個模組對應一個 AudioNode。AudioContext 可以控制它所包含的節點的建立,以及音訊處理、解碼操作的執行。做任何事情之前都要先建立 AudioContext 物件,因為一切都發生在這個環境之中。
AudioContext 播放聲音
先請求音訊檔案,放到 ArrayBuffer 裡面,然後用 AudioContext 的 API 進行 decode 解碼,解碼完了再讓它去 play。
function request (url) { return new Promise (resolve => { let xhr = new XMLHttpRequest(); xhr.open('GET', url); // set response Type arraybuffer xhr.responseType = 'arraybuffer'; xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { resolve(xhr.response); } }; xhr.send(); }); }實例化 AudioContext // Safari 是使用 webkit 前綴
let context = new (window.AudioContext || window.webkitAudioContext)();解碼播放
function play (context, decodeBuffer) { let source = context.createBufferSource(); source.buffer = decodeBuffer; source.connect(context.destination); // 从0s开始播放 source.start(0); } // 请求音频数据 let audioMedia = await request(url); // 进行decode和play context.decodeAudioData(audioMedia, decode => play(context, decode));
AudioContext 建立時機
頁面載入時建立
那麼 resume() 在使用者與頁面進行互動之後(例如,使用者單擊按鈕),您必須在某個時間進行呼叫。
// Existing code unchanged. window.onload = function() { var context = new AudioContext(); // Setup all nodes ... } // One-liner to resume playback when user interacted with the page. document.querySelector('button').addEventListener('click', function() { context.resume().then(() => { console.log('Playback resumed successfully'); }); });document.querySelector('button').addEventListener('click', function() { var context = new AudioContext(); // Setup all nodes ... });在使用者與該頁面進行互動時建立。
