You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WKWebView中视频内联播放与iOS原生全屏控制器兼容问题

解决方案

要在iOS的WKWebView中实现视频内联播放同时使用原生全屏控制器,需要从HTML配置、WKWebView设置、JS事件拦截和原生处理几个层面配合解决:

1. 确保HTML视频标签的核心属性

给<video>标签添加内联播放必须的属性,兼容iOS旧版本:

<video 
  playsinline 
  webkit-playsinline
  <!-- 其他属性如src、controls等 -->
></video>

如果使用第三方封装的播放器,要确认它允许传入这些属性,或内部已正确配置,避免覆盖关键设置。

2. WKWebView的基础配置

除了allowsInlineMediaPlayback = true,还需补充以下配置:

let config = WKWebViewConfiguration()
// 允许内联播放
config.allowsInlineMediaPlayback = true
// 允许无需用户触发的播放(按需设置,若仅用户点击播放可保留默认值)
config.mediaTypesRequiringUserActionForPlayback = []
// 保留画中画能力(与原生全屏控制器兼容)
config.allowsPictureInPictureMediaPlayback = true

3. 拦截WebView内全屏请求,交由原生处理

开启内联播放后,WebView会默认在内部模拟全屏,而非调用原生控制器。需要通过JS拦截全屏事件,通知原生启动AVPlayerViewController实现原生全屏:

注入JS脚本拦截事件

向WKWebView注入以下脚本,拦截视频的全屏请求并通过消息通知原生:

// 拦截全屏状态变化事件
document.addEventListener('webkitfullscreenchange', function(e) {
  const video = e.target;
  if (video.tagName === 'VIDEO') {
    e.preventDefault(); // 阻止WebView内部模拟全屏的默认行为
    const action = document.webkitFullscreenElement ? 'enter' : 'exit';
    window.webkit.messageHandlers.videoFullscreen.postMessage({
      action: action,
      videoId: video.id,
      currentTime: video.currentTime
    });
  }
});

// 重写视频的全屏请求方法
HTMLVideoElement.prototype.requestFullscreen = function() {
  window.webkit.messageHandlers.videoFullscreen.postMessage({
    action: 'enter',
    videoId: this.id,
    currentTime: this.currentTime
  });
};

原生代码处理消息,启动原生播放器

在iOS代码中注册消息处理器,收到JS的全屏请求后,用AVPlayerViewController展示视频:

// 初始化WKWebView时添加脚本和消息处理器
let jsCode = "// 上面的JS代码"
let userScript = WKUserScript(source: jsCode, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
config.userContentController.addUserScript(userScript)
config.userContentController.add(self, name: "videoFullscreen")

// 实现WKScriptMessageHandler协议
extension YourViewController: WKScriptMessageHandler {
  func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    guard message.name == "videoFullscreen", 
          let body = message.body as? [String: Any],
          let action = body["action"] as? String else { return }
    
    switch action {
    case "enter":
      guard let videoId = body["videoId"] as? String else { return }
      // 获取视频播放地址
      webView.evaluateJavaScript("document.getElementById('\(videoId)').currentSrc") { [weak self] result, error in
        guard let self = self, let urlStr = result as? String, let url = URL(string: urlStr) else { return }
        // 创建原生播放器
        let player = AVPlayer(url: url)
        let playerVC = AVPlayerViewController()
        playerVC.player = player
        // 同步视频当前进度
        if let currentTime = body["currentTime"] as? Double {
          player.seek(to: CMTimeMakeWithSeconds(currentTime, preferredTimescale: 1))
        }
        player.play()
        self.present(playerVC, animated: true)
      }
      
    case "exit":
      // 退出全屏时同步进度到WebView中的视频
      if let playerVC = presentedViewController as? AVPlayerViewController, 
         let player = playerVC.player {
        let currentTime = CMTimeGetSeconds(player.currentTime())
        if let videoId = body["videoId"] as? String {
          webView.evaluateJavaScript("document.getElementById('\(videoId)').currentTime = \(currentTime)")
        }
        playerVC.dismiss(animated: true)
      }
      
    default: break
    }
  }
}

4. 修复页面错乱问题

页面错乱多因WebView内部模拟全屏时修改了DOM布局,除了在JS中调用e.preventDefault()阻止默认行为外,还可以:

  • 给第三方播放器的容器设置固定宽高比(比如使用aspect-ratio: 16/9),避免视频尺寸突变导致布局混乱
  • 检查第三方播放器是否有自定义全屏样式,禁用其内部的全屏布局逻辑

内容的提问来源于stack exchange,提问作者James Haskell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 16:15:30