I'm creating a TikTok clone using YouTube shorts and I would like to get the video length. To do so I have created a function in my embed html that posts a message using WKScriptMessageHandler and the userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage){
function is supposed to pick up this message and update the totalLength variable.
我正在用YouTube短片创建TikTok的克隆,我想得到视频的长度。为此,我在嵌入的html中创建了一个函数,该函数使用WKScriptMessageHandler和用户内容控制器(_userContent控制器:WKUserContent控制器,didReceive Message:WKScriptMessage){函数来获取该消息并更新totalLength变量。
But this currently does not work. The message is never sent and therefore the function above never executes. But the html func sendCurrentTime()
does execute when the WKWebView finishes loading. How can I figure out why this message is not sending?
但这目前并不奏效。消息永远不会发送,因此上面的函数永远不会执行。但是当WKWebView完成加载时,html函数sendCurrentTime()确实会执行。我如何才能弄清楚为什么这条消息没有发送?
Based on my knowledge the message does not send because the web view is configured incorrectly or html does not have access to the web view object.
据我所知,由于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)
}
}
更多回答
优秀答案推荐
I did a quick test on my own project. Seems like the sequence of passing the configuration to Webview matters.
我对自己的项目做了一个快速测试。将配置传递给WebView的顺序似乎很重要。
This does not work. Cannot get the callback if the web view is initialized first without setting the userContentController.
这不管用。如果在未设置用户内容控制器的情况下首先初始化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
This works!
这很管用!
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
更多回答
我是一名优秀的程序员,十分优秀!