我正在使用 YouTube 短片创建 TikTok 克隆,我想获取视频长度。为此,我在嵌入 html 中创建了一个函数,该函数使用 WKScriptMessageHandler 发布消息,并且
userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage){
函数应该获取此消息并更新totalLength 变量。
但这目前不起作用。该消息永远不会发送,因此上面的函数永远不会执行。但是 html func
sendCurrentTime()
会在 WKWebView 加载完成时执行。我怎样才能找出为什么这条消息没有发送?
据我所知,消息未发送,因为 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