Swift 3中退出全屏时AVPlayerViewController报错问题
我之前在做类似的YouTube嵌入播放功能时,也碰到过这个AVPlayerViewController的报错,结合你的代码和问题场景,给你几个针对性的解决方案:
首先还原你的问题场景:
将当应用退出全屏且界面UI向上滑动时,控制台出现如下报错信息:
-[AVPlayerViewController exitFullScreenAnimated:completionHandler:] failed with error View needs to be loaded before you can call -[AVPlayerViewController (0x1028b5000) exitFullScreenAnimated:completionHandler:]!
你的实现方式是通过UIWebView嵌入YouTube iframe播放视频,相关代码如下:
var webView = UIWebView(frame: self.view.frame) webView.allowsInlineMediaPlayback = true webView.mediaPlaybackRequiresUserAction = false embededHTML = "<html><body style='margin:0px;padding:0px;'><script type='text/javascript' src='http://www.youtube.com/iframe_api'></script><script type='text/javascript'>function onYouTubeIframeAPIReady(){ytplayer=new YT.Player('playerId',{events:{onReady:onPlayerReady}})}function onPlayerReady(a){a.target.playVideo();}</script><iframe id='playerId' type='text/html' width='\(self.view.frame.size.width)' height=\(frameHeight) src='http://www.youtube.com/embed/\(youtube_code)?enablejsapi=1&rel=0&playsinline=1&autoplay=1&showinfo=0&modestbranding=0' frameborder='0'></body></html>" @IBAction func playVideo(_ sender: Any) { if let webView = webView { self.view.bringSubview(toFront: webView) webView.scrollView.isScrollEnabled = false; webView.scrollView.bounces = false; // Load your webView with the HTML we just set up webView.loadHTMLString(embededHTML, baseURL: Bundle.main.bundleURL) } }
1. 替换UIWebView为WKWebView(优先推荐)
UIWebView已经在iOS 12之后被苹果废弃,它对媒体播放的兼容性和稳定性都远不如WKWebView。换成WKWebView后,很多底层的媒体播放问题会自动解决,这也是最彻底的解决方案。
示例代码:
import WebKit class YourViewController: UIViewController, WKNavigationDelegate { var webView: WKWebView! override func viewDidLoad() { super.viewDidLoad() let webConfiguration = WKWebViewConfiguration() // 允许内联媒体播放 webConfiguration.allowsInlineMediaPlayback = true // 允许自动播放(无需用户交互触发) webConfiguration.mediaTypesRequiringUserActionForPlayback = [] webView = WKWebView(frame: self.view.frame, configuration: webConfiguration) webView.navigationDelegate = self view.addSubview(webView) } @IBAction func playVideo(_ sender: Any) { let frameHeight = self.view.frame.size.height // 替换为你实际的高度值 let youtube_code = "YOUR_TARGET_VIDEO_ID" // 替换为你的YouTube视频ID let embededHTML = "<html><body style='margin:0px;padding:0px;'><script type='text/javascript' src='http://www.youtube.com/iframe_api'></script><script type='text/javascript'>function onYouTubeIframeAPIReady(){ytplayer=new YT.Player('playerId',{events:{onReady:onPlayerReady}})}function onPlayerReady(a){a.target.playVideo();}</script><iframe id='playerId' type='text/html' width='\(self.view.frame.size.width)' height=\(frameHeight) src='http://www.youtube.com/embed/\(youtube_code)?enablejsapi=1&rel=0&playsinline=1&autoplay=1&showinfo=0&modestbranding=0' frameborder='0'></body></html>" webView.loadHTMLString(embededHTML, baseURL: Bundle.main.bundleURL) self.view.bringSubview(toFront: webView) // 控制WKWebView的滚动属性 webView.scrollView.isScrollEnabled = false webView.scrollView.bounces = false } }
2. 监听YouTube播放器全屏状态,同步控制WebView滚动
问题的核心可能是:播放器还没完全完成退出全屏的流程时,界面滚动触发了AVPlayerViewController的错误调用。你可以通过YouTube的JS API监听全屏状态变化,通知原生代码调整滚动权限。
步骤1:修改HTML中的JS代码,添加全屏状态监听
function onYouTubeIframeAPIReady(){ ytplayer=new YT.Player('playerId',{ events:{ onReady:onPlayerReady, onStateChange:onPlayerStateChange } }) } function onPlayerStateChange(event) { // 监听全屏状态切换 if (ytplayer.isFullscreen()) { // 进入全屏,通知原生禁止滚动 window.webkit.messageHandlers.fullScreenChange.postMessage("enter"); } else { // 退出全屏,延迟一点再允许滚动(确保播放器状态完全稳定) setTimeout(() => { window.webkit.messageHandlers.fullScreenChange.postMessage("exit"); }, 300); } }
步骤2:原生代码中接收JS通知,控制滚动
// 在viewDidLoad的WKWebView配置中添加消息处理器 webConfiguration.userContentController.add(self, name: "fullScreenChange") // 实现WKScriptMessageHandler协议 extension YourViewController: WKScriptMessageHandler { func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { if message.name == "fullScreenChange", let status = message.body as? String { switch status { case "enter": webView.scrollView.isScrollEnabled = false case "exit": webView.scrollView.isScrollEnabled = true default: break } } } }
3. 调整YouTube iframe参数
确保你的iframe URL中包含fs=1(明确允许全屏播放),同时确认playsinline=1参数正确设置,避免播放器状态异常。修改后的iframe src示例:
http://www.youtube.com/embed/\(youtube_code)?enablejsapi=1&rel=0&playsinline=1&autoplay=1&showinfo=0&modestbranding=0&fs=1
优先推荐第一种方案,因为WKWebView是苹果当前主推的Web组件,不仅能解决这个报错,还能提升整体性能和兼容性。
内容的提问来源于stack exchange,提问作者Jasur Rajabov

