如何在 iPad 上使用 Youtube iFrame API 修复 "If playback doesn't begin shortly, try restarting your device"?
How to fix "If playback doesn't begin shortly, try restarting your device" using Youtube iFrame API on iPad?
我创建了一个小的 YouTube 流媒体脚本,它随机播放 YouTube 音乐视频或来自 queue。直到本周之前几个月都运行良好,在使用 iPad/iPhone 时似乎不想加载视频。我收到以下错误:
If playback doesn't begin shortly, try restarting your device
我试过的:
我试过 Safari、Chrome、Firefox 和 Opera,它们都出错了。我试过清除网站 data/cache,重新启动设备,完全重新启动设备。什么都不管用。奇怪的是,它在 Windows 桌面上运行得非常好,这让我相信这不是代码中的错误,而是在 API 或 Safari 中发生了变化。我的代码最近也没有被编辑,这可能导致它停止工作。
我试过使用 jsconsole.com 调试它,没有弹出任何可疑的东西。在某些情况下,播放器会加载,视频的标题会显示,图像也会显示,但大约 30 秒后,上面的错误会与加载微调器一起显示。
我知道 playVideo();在 iOS 设备上不起作用(自动播放)。这很好,同样,该脚本以前也有效,我只需要在 first 视频上按播放键即可。但是现在,似乎 iOS 正在尝试 auto-play 视频。所以,我也通过删除 playVideo() 调用进行了测试,问题仍然存在。
在 iPad 2、iPad mini 和 iPhone 4 上进行了测试(所有设备都使用最新的 iOS,并且之前都可以正常工作)。
我不知所措,正试图在周末之前为家庭聚会解决这个问题 :) 因此,对于可能导致 iOS 失败的原因的任何帮助或提示,我将不胜感激。
这里是javascript代码:
// 2. This code loads the IFrame Player API code asynchronously.
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// 3. This function creates an <iframe> (and YouTube player)
// after the API code downloads.
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
check_queue_timer = setTimeout(check_queue(),3000);
}
// 5. The API calls this function when the player's state changes.
// The function indicates that when playing a video (state=1),
// the player should play for six seconds and then stop.
var done = false;
function onPlayerStateChange(event) {
if (event.data === 0) {
// TRACK AS DONE, REFRESH QUEUE AND GET NEXT SONG
// POST TO WRITE TO FILE
$.ajax({
type: 'POST',
url: site_url+'ajax_next_track',
dataType: 'json',
data: 'queue_id='+$('#queue_id').val(),
cache: false,
success:
function(data){
if(data.status == 'success'){
$("#queue_table").empty();
if(data.queue.length == 0){
check_queue_timer = setTimeout(check_queue(),3000);
}
$.each(data.queue, function(i, item) {
if(i == 0){
event.target.loadVideoById(item.video_id);
event.target.playVideo();
$('#queue_id').val(item.queue_id);
}
$('#queue_table').append('<tr><td>'+item.title+'</td></tr>');
});
}
else{
console(data.message);
}
},
error:
function( jqXHR, textStatus, errorThrown ){
$('#error_msg').html('Something broke.').fadeIn();
}
});
}
}
function stopVideo() {
player.stopVideo();
}
function check_queue(){
$.ajax({
type: 'POST',
url: site_url+'ajax_next_track',
dataType: 'json',
data: 'no_delete=1',
cache: false,
success:
function(data){
if(data.status == 'success'){
$("#queue_table").empty();
if(data.queue.length == 0){
clearTimeout(check_queue_timer);
check_queue_timer = setTimeout(check_queue(),3000);
}
$.each(data.queue, function(i, item) {
if(i == 0){
player.loadVideoById(item.video_id);
player.playVideo();
$('#queue_id').val(item.queue_id);
clearTimeout(check_queue_timer);
}
$('#queue_table').append('<tr><td>'+item.title+'</td></tr>');
});
}
else{
console(data.message);
}
},
error:
function( jqXHR, textStatus, errorThrown ){
$('#error_msg').html('Something broke.').fadeIn();
}
});
}
更新 1(2015 年 11 月 25 日)
我决定从头开始,使用 https://developers.google.com/youtube/iframe_api_reference 上的示例代码。 loadVideoById() 似乎不再适用于 iPads。这是以前。如果我不包含 loadVideoById() 或 playVideo() 它会起作用。理想情况下,我希望它与 loadVideoById() 一起使用。
我遇到了类似的问题并进行了一些挖掘,结果发现 Apple 已经删除了通过脚本等自动播放嵌入项目的功能,因此最终用户不会意外用完他们的数据。用户需要自己触发播放按钮。
解决此问题的最佳方法是检查用户是使用移动设备还是桌面设备并设置一个变量 (true/false)。
这就是我所做的
var mobileDevice = false;
if(typeof window.orientation !== 'undefined'){
var mobileDevice = true;
}
if(!mobileDevice) ytPlayer.playVideo();
希望对您有所帮助。
Source (https://developer.apple.com)
To prevent unsolicited downloads over cellular networks at the user’s
expense, embedded media cannot be played automatically in Safari on
iOS—the user always initiates playback.
这里有更多答案 - YouTube API not working with iPad / iPhone / non-Flash device
为了解决这个问题,我用脑袋撞了好几个小时……这就是我的发现。
这是因为 Apple 严苛的 iOS 限制:网页只能在直接响应用户反馈时开始播放 audio/video。 (请注意,此限制仅影响 第一次 时间 audio/video 在页面上播放。)
通常,要绕过 Apple 的限制,确保您的 play() 调用直接发生在事件处理程序(例如,点击处理程序)中就足够了。这适用于网络音频 API 和普通 HTML5 视频 -- 但 YouTube 播放器的一些问题阻止它对 YouTube 起作用。
因此,YouTube 的解决方案显然是要求用户单击 YouTube 视频本身以启动播放。从那时起,您可以使用 YouTube iframe API 控制它(播放、暂停、搜索等)。但是您无法使用 API 控制 YouTube 视频,直到 在 用户点击视频后。
为了获得万无一失的用户体验,您可以隐藏所有播放器控制 UI 并告诉用户单击 YouTube 视频本身开始播放。然后,一旦用户点击了一次视频,您就可以激活您的 UI。当然,你应该设计这个只适用于iOS.
谢谢你的头痛,Apple!
如果问题是其他两个答案(Adrian 和 Junior)所说的,那么应该可以通过访问 UIWebView
(或 WKWebView
)并设置 mediaPlaybackRequiresUserAction
轻松解决旗帜。如果您推出自己的解决方案或使用官方框架 (https://github.com/youtube/youtube-ios-player-helper),就可以做到这一点。
Swift
let playerView = YTPlayerView()
playerView.webView.mediaPlaybackRequiresUserAction = false
我在笔记本电脑上安装 DPS 音频应用程序后遇到了这个问题。这些应用程序将我现有的音频驱动程序修改为他们的 "Speakers (Digital Power Station)" 音频设备。
通过阅读 Reddit post,我将音频设备替换为我的笔记本电脑的来源。这样,我的问题就解决了。
我创建了一个小的 YouTube 流媒体脚本,它随机播放 YouTube 音乐视频或来自 queue。直到本周之前几个月都运行良好,在使用 iPad/iPhone 时似乎不想加载视频。我收到以下错误:
If playback doesn't begin shortly, try restarting your device
我试过的:
我试过 Safari、Chrome、Firefox 和 Opera,它们都出错了。我试过清除网站 data/cache,重新启动设备,完全重新启动设备。什么都不管用。奇怪的是,它在 Windows 桌面上运行得非常好,这让我相信这不是代码中的错误,而是在 API 或 Safari 中发生了变化。我的代码最近也没有被编辑,这可能导致它停止工作。
我试过使用 jsconsole.com 调试它,没有弹出任何可疑的东西。在某些情况下,播放器会加载,视频的标题会显示,图像也会显示,但大约 30 秒后,上面的错误会与加载微调器一起显示。
我知道 playVideo();在 iOS 设备上不起作用(自动播放)。这很好,同样,该脚本以前也有效,我只需要在 first 视频上按播放键即可。但是现在,似乎 iOS 正在尝试 auto-play 视频。所以,我也通过删除 playVideo() 调用进行了测试,问题仍然存在。
在 iPad 2、iPad mini 和 iPhone 4 上进行了测试(所有设备都使用最新的 iOS,并且之前都可以正常工作)。
我不知所措,正试图在周末之前为家庭聚会解决这个问题 :) 因此,对于可能导致 iOS 失败的原因的任何帮助或提示,我将不胜感激。
这里是javascript代码:
// 2. This code loads the IFrame Player API code asynchronously.
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// 3. This function creates an <iframe> (and YouTube player)
// after the API code downloads.
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
check_queue_timer = setTimeout(check_queue(),3000);
}
// 5. The API calls this function when the player's state changes.
// The function indicates that when playing a video (state=1),
// the player should play for six seconds and then stop.
var done = false;
function onPlayerStateChange(event) {
if (event.data === 0) {
// TRACK AS DONE, REFRESH QUEUE AND GET NEXT SONG
// POST TO WRITE TO FILE
$.ajax({
type: 'POST',
url: site_url+'ajax_next_track',
dataType: 'json',
data: 'queue_id='+$('#queue_id').val(),
cache: false,
success:
function(data){
if(data.status == 'success'){
$("#queue_table").empty();
if(data.queue.length == 0){
check_queue_timer = setTimeout(check_queue(),3000);
}
$.each(data.queue, function(i, item) {
if(i == 0){
event.target.loadVideoById(item.video_id);
event.target.playVideo();
$('#queue_id').val(item.queue_id);
}
$('#queue_table').append('<tr><td>'+item.title+'</td></tr>');
});
}
else{
console(data.message);
}
},
error:
function( jqXHR, textStatus, errorThrown ){
$('#error_msg').html('Something broke.').fadeIn();
}
});
}
}
function stopVideo() {
player.stopVideo();
}
function check_queue(){
$.ajax({
type: 'POST',
url: site_url+'ajax_next_track',
dataType: 'json',
data: 'no_delete=1',
cache: false,
success:
function(data){
if(data.status == 'success'){
$("#queue_table").empty();
if(data.queue.length == 0){
clearTimeout(check_queue_timer);
check_queue_timer = setTimeout(check_queue(),3000);
}
$.each(data.queue, function(i, item) {
if(i == 0){
player.loadVideoById(item.video_id);
player.playVideo();
$('#queue_id').val(item.queue_id);
clearTimeout(check_queue_timer);
}
$('#queue_table').append('<tr><td>'+item.title+'</td></tr>');
});
}
else{
console(data.message);
}
},
error:
function( jqXHR, textStatus, errorThrown ){
$('#error_msg').html('Something broke.').fadeIn();
}
});
}
更新 1(2015 年 11 月 25 日)
我决定从头开始,使用 https://developers.google.com/youtube/iframe_api_reference 上的示例代码。 loadVideoById() 似乎不再适用于 iPads。这是以前。如果我不包含 loadVideoById() 或 playVideo() 它会起作用。理想情况下,我希望它与 loadVideoById() 一起使用。
我遇到了类似的问题并进行了一些挖掘,结果发现 Apple 已经删除了通过脚本等自动播放嵌入项目的功能,因此最终用户不会意外用完他们的数据。用户需要自己触发播放按钮。
解决此问题的最佳方法是检查用户是使用移动设备还是桌面设备并设置一个变量 (true/false)。
这就是我所做的
var mobileDevice = false;
if(typeof window.orientation !== 'undefined'){
var mobileDevice = true;
}
if(!mobileDevice) ytPlayer.playVideo();
希望对您有所帮助。
Source (https://developer.apple.com)
To prevent unsolicited downloads over cellular networks at the user’s expense, embedded media cannot be played automatically in Safari on iOS—the user always initiates playback.
这里有更多答案 - YouTube API not working with iPad / iPhone / non-Flash device
为了解决这个问题,我用脑袋撞了好几个小时……这就是我的发现。
这是因为 Apple 严苛的 iOS 限制:网页只能在直接响应用户反馈时开始播放 audio/video。 (请注意,此限制仅影响 第一次 时间 audio/video 在页面上播放。)
通常,要绕过 Apple 的限制,确保您的 play() 调用直接发生在事件处理程序(例如,点击处理程序)中就足够了。这适用于网络音频 API 和普通 HTML5 视频 -- 但 YouTube 播放器的一些问题阻止它对 YouTube 起作用。
因此,YouTube 的解决方案显然是要求用户单击 YouTube 视频本身以启动播放。从那时起,您可以使用 YouTube iframe API 控制它(播放、暂停、搜索等)。但是您无法使用 API 控制 YouTube 视频,直到 在 用户点击视频后。
为了获得万无一失的用户体验,您可以隐藏所有播放器控制 UI 并告诉用户单击 YouTube 视频本身开始播放。然后,一旦用户点击了一次视频,您就可以激活您的 UI。当然,你应该设计这个只适用于iOS.
谢谢你的头痛,Apple!
如果问题是其他两个答案(Adrian 和 Junior)所说的,那么应该可以通过访问 UIWebView
(或 WKWebView
)并设置 mediaPlaybackRequiresUserAction
轻松解决旗帜。如果您推出自己的解决方案或使用官方框架 (https://github.com/youtube/youtube-ios-player-helper),就可以做到这一点。
Swift
let playerView = YTPlayerView()
playerView.webView.mediaPlaybackRequiresUserAction = false
我在笔记本电脑上安装 DPS 音频应用程序后遇到了这个问题。这些应用程序将我现有的音频驱动程序修改为他们的 "Speakers (Digital Power Station)" 音频设备。
通过阅读 Reddit post,我将音频设备替换为我的笔记本电脑的来源。这样,我的问题就解决了。