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

Swift中请求YouTube Shorts当前时长后视频无响应问题排查

问题原因分析
  • 未清理的定时器引发资源泄漏:每次加载新视频时,旧的SmartReelView实例及其关联的定时器并未被销毁,多个定时器会同时调用evaluateJavaScript,频繁干扰YouTube播放器的内部状态,最终导致播放异常甚至冻结。
  • 错误的跨端通信逻辑:通过抛出Error传递当前时间违背了evaluateJavaScript的设计意图——该方法的错误回调仅用于捕获JS执行异常,频繁触发错误处理会导致WebKit内部状态紊乱,进而影响播放器稳定性。
  • 时间精度丢失与匹配失败:原正则表达式Current Time: (\\d+)仅能匹配整数,而YouTube的getCurrentTime()返回浮点数,不仅会丢失时间精度,还可能因匹配失败引发不必要的逻辑执行,加重状态异常。
修复方案

1. 管理定时器生命周期,避免资源泄漏

在Coordinator中持有定时器引用,确保视图销毁或加载新内容时及时清理旧定时器:

class Coordinator: NSObject, WKNavigationDelegate {
    var parent: SmartReelView
    var updateTimer: Timer? // 持有定时器引用

    init(_ parent: SmartReelView) {
        self.parent = parent
    }
    
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        // 先销毁旧定时器,避免重复触发
        updateTimer?.invalidate()
        updateTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
            guard let self = self, self.parent.isPlaying else { return }
            webView.evaluateJavaScript("sendCurrentTime()", completionHandler: { (result, _) in
                // 直接接收返回值,不再依赖错误回调
                if let currentTime = result as? Double {
                    self.parent.currentTime = currentTime
                }
            })
        }
    }
    
    // 视图销毁时自动清理定时器
    deinit {
        updateTimer?.invalidate()
    }
}

2. 修正JS函数,直接返回当前时间

修改sendCurrentTime函数,不再抛出错误,而是直接返回时间值,符合evaluateJavaScript的正常使用逻辑:

function sendCurrentTime() {
    var videoState = player.getPlayerState();
    if (videoState === YT.PlayerState.PLAYING) {
        return player.getCurrentTime();
    }
    return null; // 非播放状态返回null,避免无效值传递
}

3. 处理视频切换时的资源清理

在updateUIView中检测视频链接变化,及时清理旧定时器并重新加载内容:

func updateUIView(_ uiView: WKWebView, context: Context) {
    // 检查当前加载的视频是否与新链接一致,避免重复加载
    let currentVideoId = uiView.configuration.userContentController.userScripts.first?.source.contains(link) ?? false
    if !currentVideoId {
        context.coordinator.updateTimer?.invalidate()
        loadInitialContent(web: uiView)
    }
}

4. 优化WebView初始化逻辑

将滚动禁用逻辑移到初始化阶段,避免重复设置:

func makeUIView(context: Context) -> WKWebView {
    let webConfiguration = WKWebViewConfiguration()
    webConfiguration.allowsInlineMediaPlayback = true
    let webview = WKWebView(frame: .zero, configuration: webConfiguration)
    webview.navigationDelegate = context.coordinator
    webview.scrollView.isScrollEnabled = false
    loadInitialContent(web: webview)
    return webview
}
额外优化建议
  • 利用YouTube IFrame API的onStateChange事件同步播放状态,减少定时器轮询的频率。
  • 改用WKUserContentController的消息推送机制(window.webkit.messageHandlers.postMessage),让JS主动向Swift发送当前时间,替代定时器轮询,提升性能与稳定性。

内容的提问来源于stack exchange,提问作者Ahmed Zaidan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 14:05:34