【问题标题】:How to handle "Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first." on Desktop with Chrome 66?如何处理“未捕获(承诺)DOMException:play() 失败,因为用户没有先与文档交互。”在桌面上使用 Chrome 66?
【发布时间】:2018-09-30 12:34:36
【问题描述】:

我收到错误消息..

Uncaught (in promise) DOMException: play() failed 因为用户没有先与文档交互。

..尝试使用 Chrome 66 版在桌面上播放视频时。

我确实找到了一个在网站上自动开始播放但使用以下 HTML 的广告:

<video
    title="Advertisement"
    webkit-playsinline="true"
    playsinline="true"
    style="background-color: rgb(0, 0, 0); position: absolute; width: 640px; height: 360px;"
    src="http://ds.serving-sys.com/BurstingRes/Site-2500/Type-16/1ff26f6a-aa27-4b30-a264-df2173c79623.mp4"
    autoplay=""></video>

那么绕过 Chrome v66 的自动播放拦截器真的像在 &lt;video&gt; 元素中添加 webkit-playsinline="true"playsinline="true"autoplay="" 属性一样简单吗?这样做有什么负面影响吗?

【问题讨论】:

  • 我认为 playinline 是 iOS 的东西。
  • @everyone:youtube 如何绕过“无用户交互”规则?

标签: javascript google-chrome video html5-video


【解决方案1】:

回答手头的问题...
不,仅仅拥有这些属性是不够的,要能够自动播放带有音频的媒体,您需要在文档上注册用户手势。

但是,这个限制非常弱:如果您确实在父文档上收到了这个用户手势,并且您的视频是从 iframe 加载的,那么您可以播放它...

所以以this fiddle为例,这只是

<video src="myvidwithsound.webm" autoplay=""></video>

第一次加载,如果你不点击任何地方,它就不会运行,因为我们还没有注册任何事件。
但是,一旦您单击 “运行” 按钮,父文档 (jsfiddle.net) 确实收到了用户手势,现在视频开始播放,即使它在技术上加载到不同的文档中。

但是下面的sn-p,因为它需要你实际点击Run code sn-p按钮,所以会自动播放。

&lt;video src="https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm" autoplay=""&gt;&lt;/video&gt;

这意味着您的广告可能能够播放,因为您确实向主页提供了用户手势。


现在,请注意 Safari 和移动 Chrome 有比这更严格的规则,并且要求您以编程方式在用户事件处理程序本身的 &lt;video&gt;&lt;audio&gt; 元素上实际触发至少一次 play() 方法.

btn.onclick = e => {
  // mark our MediaElement as user-approved
  vid.play().then(()=>vid.pause());
  // now we can do whatever we want at any time with this MediaElement
  setTimeout(()=> vid.play(), 3000);
};
<button id="btn">play in 3s</button>
<video
  src="https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm" id="vid"></video>

如果您不需要音频,那么就不要将其附加到您的媒体上,只有一个视频轨道的视频也可以自动播放,这将减少您用户的带宽使用。

【讨论】:

  • @JanTuroň 不,你不能。 .play.pause 方法需要直接从 HTMLMediaElement 实例中调用,或者你需要创建方法的绑定副本,例如vid.play.then(vid.pause.bind(vid)),这并不比简单的vid.play.then(()=&gt;vid.pause()) 更容易阅读。
【解决方案2】:

在地址栏中输入Chrome://flags

搜索:自动播放

自动播放政策

决定是否允许音频或视频时使用的策略 自动播放。

– Mac、Windows、Linux、Chrome 操作系统、Android

将此设置为“无需用户手势

重新启动 Chrome,您无需更改任何代码

【讨论】:

  • 你不可能要求每个用户去改变设置。
  • 这实际上可以解决某些人的问题(信息亭、私人和本地网站...),但在 Chrome 76 中删除了该标志。现在唯一的解决方案是 this answer
【解决方案3】:
  1. 打开chrome://settings/content/sound
  2. 设置不需要用户手势
  3. 重新启动 Chrome

【讨论】:

  • 自动播放策略更改。 Click me
  • 它仅用于开发者在本地测试 Chrome 自动播放策略行为。 developers.google.com/web/updates/2017/09/…
  • 我发现命令行标志--autoplay-policy=no-user-gesture-required是实现这个设置的程序化方式。
  • 这仅适用于您的浏览器,其他人仍会受到影响
  • 谁支持这个答案?这不是 superuser.com。本地机器的解决方案不能是可接受的答案。
【解决方案4】:

要在 chrome 66 更新后自动播放 html 5 元素,您只需将 muted 属性添加到视频元素。

所以你当前的视频 HTML

<video
    title="Advertisement"
    webkit-playsinline="true"
    playsinline="true"
    style="background-color: rgb(0, 0, 0); position: absolute; width: 640px; height: 360px;"
    src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
    autoplay=""></video>

只需要muted="muted"

<video
    title="Advertisement"
    style="background-color: rgb(0, 0, 0); position: absolute; width: 640px; height: 360px;"
    src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
    autoplay="true"
    muted="muted"></video>

我相信 chrome 66 更新试图阻止标签在用户标签上产生随机噪音。这就是为什么 muted 属性使自动播放再次起作用的原因。

【讨论】:

  • 有没有办法在视频开始播放后立即启用音频?删除mute 属性或设置volume 属性没有帮助。
  • 我不得不改用muted="true"
  • 最好设置muted=true OR muted=false
  • 你也可以写muted至少对我有用。
  • 我的
【解决方案5】:

我发现的最佳解决方案是使视频静音

HTML

<video loop muted autoplay id="videomain">
  <source src="videoname.mp4" type="video/mp4">
</video>

【讨论】:

    【解决方案6】:

    我在使用 Android 手机时遇到了一些问题。 经过几次尝试,我发现当数据保护程序打开时没有自动播放:

    如果启用Data Saver 模式,则不会自动播放。如果启用流量节省模式,则在媒体设置中禁用自动播放。

    Source

    【讨论】:

      【解决方案7】:

      尝试使用 mousemove 事件监听器

      var audio = document.createElement("AUDIO")
      document.body.appendChild(audio);
      audio.src = "./audio/rain.m4a"
      
      document.body.addEventListener("mousemove", function () {
          audio.play()
      })
      

      【讨论】:

        【解决方案8】:

        Chrome 需要用户交互才能自动播放或通过 js (video.play()) 播放视频。 但互动可以是任何类型的,在任何时候。 如果您只是在页面上随机单击,视频将自动播放。 然后我解决了,添加了一个按钮(仅在 chrome 浏览器上),上面写着“启用视频自动播放”。该按钮什么都不做,只是单击它,是任何其他视频所需的用户交互。

        【讨论】:

          【解决方案9】:

          对我(在 Angular 项目中)来说,这段代码有帮助:

          在 HTML 中你应该添加autoplay muted

          在 JS/TS 中

          playVideo() {
              const media = this.videoplayer.nativeElement;
              media.muted = true; // without this line it's not working although I have "muted" in HTML
              media.play();
          }
          

          【讨论】:

          • 绝对真实且令人难以置信,即使使用最新的 Angular 版本 Ng8。 Angular 根本不关心组件的 HTML 模板上发生了什么!
          • 并且,使用新的Angular使用@ViewChild()的方式,您需要将静态选项设置为true:@ViewChild('videoPlayer', {static: true}) videoplayer: ElementRef;video: HTMLVideoElement;然后:this.video = this.videoplayer.nativeElement;@ngOnInit()
          • 这是我的问题,在 HTML 中静音被完全忽略,我不得不通过 JS 强制它。经过几天的搜索,您的答案 + 100 万
          • 哇,不敢相信我真的需要 Angular SSR 加载后视图的 javascript 端静音。一直以来,我都认为 HTML 是问题所在。
          【解决方案10】:

          我在尝试播放音频文件时遇到了类似的错误。起初,它可以工作,然后当我开始在同一个函数中使用 ChangeDetector 的 markForCheck 方法以在承诺解决时触发重新渲染时它停止工作(我遇到了视图渲染问题)。

          当我将 markForCheck 更改为 detectChanges 时,它又开始工作了。我真的无法解释发生了什么,我只是想把它放在这里,也许它会对某人有所帮助。

          【讨论】:

            【解决方案11】:

            扩展 DOM 元素、处理错误并优雅地降级

            下面我使用原型函数来包装原生的DOM播放函数,抓取它的promise,然后如果浏览器抛出异常就降级为播放按钮。此扩展解决了浏览器的缺点,并且可以在任何了解目标元素的页面中即插即用。

            // JavaScript
            // Wrap the native DOM audio element play function and handle any autoplay errors
            Audio.prototype.play = (function(play) {
            return function () {
              var audio = this,
                  args = arguments,
                  promise = play.apply(audio, args);
              if (promise !== undefined) {
                promise.catch(_ => {
                  // Autoplay was prevented. This is optional, but add a button to start playing.
                  var el = document.createElement("button");
                  el.innerHTML = "Play";
                  el.addEventListener("click", function(){play.apply(audio, args);});
                  this.parentNode.insertBefore(el, this.nextSibling)
                });
              }
            };
            })(Audio.prototype.play);
            
            // Try automatically playing our audio via script. This would normally trigger and error.
            document.getElementById('MyAudioElement').play()
            
            <!-- HTML -->
            <audio id="MyAudioElement" autoplay>
              <source src="https://www.w3schools.com/html/horse.ogg" type="audio/ogg">
              <source src="https://www.w3schools.com/html/horse.mp3" type="audio/mpeg">
              Your browser does not support the audio element.
            </audio>
            

            【讨论】:

            • 这是一个非常聪明的方法,不会破坏任何策略(因为无论如何播放都不会开始),并且可以防止出现错误。 +1
            • 迪托。防止错误和任何政策也是我的目标。任何声音都可以等到用户交互 - 太棒了!
            【解决方案12】:

            您应该在videoElement 中添加muted 属性,以便您的代码按预期工作。看下面..

            <video id="IPcamerastream" muted="muted" autoplay src="videoplayback%20(1).mp4" width="960" height="540"></video>
            

            不要忘记添加有效的视频链接作为来源

            【讨论】:

              【解决方案13】:

              就我而言,我必须这样做

               // Initialization in the dom
               // Consider the muted attribute
               <audio id="notification" src="path/to/sound.mp3" muted></audio>
              
              
               // in the js code unmute the audio once the event happened
               document.getElementById('notification').muted = false;
               document.getElementById('notification').play();
              

              【讨论】:

              • Não funciona testei no chrome Uncaught (in promise) DOMException: play() failed 因为用户没有先与文档交互
              【解决方案14】:

              根据新的浏览器政策,用户必须先与 DOM 交互,然后才能播放 Audio 元素。

              如果你想在页面加载时播放媒体,那么你可以像这样简单地将自动播放属性添加到 HTML 中的音频元素

              &lt;video id="video" src="./music.mp4" autoplay&gt;

              或者如果您不想进行自动播放,那么您可以使用 Javascript 来处理。由于 autoplay 属性设置为 true,媒体将被播放,我们可以简单地将媒体静音。

              document.getElementById('video').autoplay = true;
              document.getElementById('video').muted = true; 
              

              Imp:现在,当您播放媒体时,不要忘记将 muted 属性设置为 false。像这样

              document.getElementById('video').muted = false; 
              document.getElementById('video').play();
              

              或者您也可以显示一个简单的弹出窗口,用户将在其中单击模式中的允许按钮。所以他先和DOM交互,然后你就什么都不用做了

              【讨论】:

                【解决方案15】:

                我收到了这个错误

                Uncaught (in promise) DOMException: play() failed 因为用户没有先与文档交互。

                这就是我在 Angular 项目中所做的事情

                关键点:永远不要假设视频会播放,也不要在视频未实际播放时显示暂停按钮。

                您应该始终查看 play 函数返回的 Promise 以查看它是否被拒绝:

                ngOnInit(): void{
                    this.ensureVideoPlays();
                }
                
                private ensureVideoPlays(): void{
                    const video = document.querySelector("video");
                
                    if(!video) return;
                    
                    const promise = video.play();
                    if(promise !== undefined){
                        promise.then(() => {
                            // Autoplay started
                        }).catch(error => {
                            // Autoplay was prevented.
                            video.muted = true;
                            video.play();
                        });
                    }
                }
                

                来源:Autoplay policy

                【讨论】:

                  【解决方案16】:

                  我遇到了类似的问题,我需要在不静音的情况下播放视频。我这样做的方式,等待一秒钟然后通过按钮触发事件。这是我的代码

                  if (playVideo == '1') {
                      setTimeout(function() {
                          $("#watch_video_btn").trigger('click');
                      }, 1000);
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 2020-12-25
                    • 1970-01-01
                    • 2020-05-02
                    • 2020-06-08
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多