我正在用YouTube短片创建TikTok的克隆,我想得到视频的长度.为此,我在嵌入的html中创建了一个函数,该函数使用WKScriptMessageHandler发布一条消息,而userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage){函数应该获取这条消息并更新totalLength变量.

但这目前并不奏效.消息永远不会发送,因此上面的函数永远不会执行.但是当WKWebView完成加载时,HTMLFunc sendCurrentTime()确实执行.我如何才能弄清楚为什么这条消息没有发送?

据我所知,由于Web视图配置不正确或html无权访问Web视图对象,所以无法发送该消息.

struct SmartReelView: UIViewRepresentable {
    let link: String
    @Binding var totalLength: Double

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    func makeUIView(context: Context) -> WKWebView {
        let webConfiguration = WKWebViewConfiguration()
        webConfiguration.allowsInlineMediaPlayback = true
        let webview = WKWebView(frame: .zero, configuration: webConfiguration)
        webview.navigationDelegate = context.coordinator

        let userContentController = WKUserContentController()
        userContentController.add(context.coordinator, name: "observe")
        webview.configuration.userContentController = userContentController

        loadInitialContent(web: webview)
        
        return webview
    }
    
    func updateUIView(_ uiView: WKWebView, context: Context) { }
    
    class Coordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler {
        var parent: SmartReelView

        init(_ parent: SmartReelView) {
            self.parent = parent
        }
        
        func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage){
            if message.name == "observe", let Time = message.body as? Double {
                parent.totalLength = Time
            }
        }
        
        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            webView.evaluateJavaScript("sendCurrentTime()", completionHandler: nil)
        }
    }
    
    private func loadInitialContent(web: WKWebView) {
        let embedHTML = """
        <style>
            body {
                margin: 0;
                background-color: black;
            }
            .iframe-container iframe {
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
            }
        </style>
        <div class="iframe-container">
            <div id="player"></div>
        </div>
        <script>
            var tag = document.createElement('script');
            tag.src = "https://www.youtube.com/iframe_api";
            var firstScriptTag = document.getElementsByTagName('script')[0];
            firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

            var player;
            var isPlaying = false;
            function onYouTubeIframeAPIReady() {
                player = new YT.Player('player', {
                    width: '100%',
                    videoId: '\(link)',
                    playerVars: { 'playsinline': 1, 'controls': 0},
                    events: {
                        'onStateChange': function(event) {
                            if (event.data === YT.PlayerState.ENDED) {
                                player.seekTo(0);
                                player.playVideo();
                            }
                        }
                    }
                });
            }
            function sendCurrentTime() {
                const length = player.getDuration();
                window.webkit.messageHandlers.observe.postMessage(length);
            }
        </script>
        """
        
        web.scrollView.isScrollEnabled = false
        web.loadHTMLString(embedHTML, baseURL: nil)
    }
}

推荐答案

我对自己的项目做了一个快速测试.将配置传递给WebView的顺序似乎很重要.

这不管用.如果在未设置用户内容控制器的情况下首先初始化Web视图,则无法获取回调.

let webConfiguration = WKWebViewConfiguration()
webConfiguration.allowsInlineMediaPlayback = true
let webview = WKWebView(frame: .zero, configuration: webConfiguration)
webview.navigationDelegate = context.coordinator

let userContentController = WKUserContentController()
userContentController.add(context.coordinator, name: "observe")
webview.configuration.userContentController = userContentController

这很管用!

let userContentController = WKUserContentController()
userContentController.add(context.coordinator, name: "observe")

let webConfiguration = WKWebViewConfiguration()
webConfiguration.allowsInlineMediaPlayback = true
webConfiguration.userContentController = userContentController

let webview = WKWebView(frame: .zero, configuration: webConfiguration)
webview.navigationDelegate = context.coordinator

Html相关问答推荐

Xpath:提取标签之间的文本,但一旦出现嵌入标签就停止

UseEffect()从不调用preact

正文不能填满浏览器100%的高度

创建一个带有div和径向渐变的全宽半圆

在NzMessageService中传递动态TemplateRef- Angular 15

使用HTML进行DAX测量

在Firefox中,使用写入模式:Vertical-LR时,不随内容扩展的css弹性项

IFRAME中的Chrome图像未调整大小

是否可以只使用css而不使用像&;nbsp;这样的HTML符号来实现断字而不换行空格?

在移动屏幕上显示时分支树视图的响应能力问题

如何从通过 find-each 方法(在 Rails 应用程序中)生成的列表创建下拉菜单?

在Firefox中使用keySplines时,SVG: <animateMotion>不起作用

Github上部署需要花费几小时时间:等待github pages部署批准

如何使用 CSS 应用带有笔划的文本阴影?

为什么我的 div 元素没有形成一个圆形时钟?

为什么使用 Css 只能看到 1 列而不是 3 列?

我正在使用 react-router-dom 并创建了一个固定的导航栏,它在每个网页上不断改变大小,我不知道为什么

具有淡入/淡出效果的 CSS 选框

无法使用 HTML 中的 Bootstrap 自上而下居中

svg 内容超过元素