首页 > 解决方案 > 在 Core Data WkWebView 中创建新对象时停止响应(SwiftUI)

问题描述

我有正在播放 YouTube 视频的 WkWebView。我已经将播放/暂停功能以及更多功能放在一起。目前,我正在尝试实现 CoreData,并尝试保存有关当前正在播放的 YT 视频的信息,例如视频标题和视频 ID 等。

我可以保存数据,也可以查看我保存的数据,也可以删除它。但是,我注意到当我尝试保存视频时,我的播放/暂停按钮不再起作用。我已经将问题追溯到我的 WkWebView 操作在保存 CoreData 后不再有效,但在我尝试保存之前它确实有效。

函数 playVideo 和 pauseVideo 被调用,但似乎 WkWebView 出于某种奇怪的原因不再响应

所以我的问题是为什么我的 WkWebView 不再响应?

这是我实现 WkWebView 的方式

var webview: WKWebView?
    var videoID: String
    let hardcodedPlaylist: [String] = ["EQIh607kd0Y", "A5kGigZHed4", "MLJyFzdQfK8", "Trfxm0TJwuQ", "nVVr7gJNny8", "XqZsoesa55w"]
    
    func createEmbededHtml(videoID: String, playlist: String) -> String {
            return """
                <!DOCTYPE html>
                   <html>
                   <style>
                       * { margin: 0; padding: 0; }
                       html, body { width: 100%; height: 100%; }
                   </style>
                    <body>
                      <!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
                      <div id="player" ></div>



                      <script>
                        // 2. This code loads the IFrame Player API code asynchronously.
                        var tag = document.createElement('script');

                        tag.src = "https://www.youtube.com/iframe_api";
                        var firstScriptTag = document.getElementsByTagName('script')[0];
                        firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

                        // 3. This function creates an <iframe> (and YouTube player)
                        //    after the API code downloads.
                        var player;
                        function onYouTubeIframeAPIReady() {
                          player = new YT.Player('player', {
                            height: '100%',
                            width: '100%',
                            videoId: '\(videoID)',
                            playerVars: {
                               controls: 0,
                               rel: 0,
                               modestbranding: 1,
                               playsinline: 1,
                               enablejsapi: 1,
                               playlist: '\(playlist)'
                           },
                            events: {
                              'onReady': onPlayerReady
                            }
                          });
                        }

                        // 4. The API will call this function when the video player is ready.
                        function onPlayerReady(event) {
                           player.playVideoAt(1);
                        }

                      </script>
                    </body>
                   </html>
                """
    }
    
    init(web: WKWebView?, videoID: String) {
        let configuration = WKWebViewConfiguration()
        configuration.allowsInlineMediaPlayback = true
        configuration.mediaTypesRequiringUserActionForPlayback = []
        self.webview = WKWebView(frame: .zero, configuration: configuration)
        self.videoID = videoID
    }
    
    func makeUIView(context: Context) -> WKWebView {
        let embededHtmlString = createEmbededHtml(videoID: videoID, playlist: hardcodedPlaylist.joined(separator: ", "))
        self.webview?.navigationDelegate = context.coordinator
        webview?.isUserInteractionEnabled = false
        webview?.isOpaque = false
        webview?.loadHTMLString(embededHtmlString, baseURL: nil)
        return webview!
    }
    
    func updateUIView(_ uiView: WKWebView, context: Context) {
    }
    
    class Coordinator: NSObject, WKNavigationDelegate {
        private var webViewModel: WebViewModel
        
        init(_ webViewModel: WebViewModel) {
            self.webViewModel = webViewModel
        }
        
        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            print("webview has loaded")
            self.webViewModel.didFinishLoading = true
        }
    
    }
    
    func makeCoordinator() -> Webview.Coordinator {
        Coordinator(webViewModel)
    }
    
    func playVideo() {
        webview?.evaluateJavaScript("player.playVideo()")
        print("playing...")
    }
    
    func pauseVideo() {
        webview?.evaluateJavaScript("player.pauseVideo()")
        print("pauseing...")
    }

这段代码在一个名为 Webview 的类中,为了显示尽可能少的代码,我不会展示我如何调用我的 Webview 我认为它不会起到任何作用。

这是一个带有用于保存视频的按钮代码的片段,我还包含了 saveVideo 和 saveContext 的代码

Button(action: {
                print("saving button pressed")
                
                let currentIndex = webViewModel.playlistIndex - 1
                saveVideo(videoID: videoIDFetcherInfo.videoIDs[webViewModel.playlistIndex] ,title: videoIDFetcherInfo.videoTitles[currentIndex], thumbnailUrlString: videoIDFetcherInfo.VideoThumbnailsUrl[currentIndex])
}, label: {
                Image(videoSaved.isVideoSaved ? "bookmark-border-filled" : "bookmark-border")
                    .sizeShadowModifier(size: 44, shadowRadius: 12, shadowX: 2, shadowY: 6)
            })

 func saveVideo(videoID: String, title: String, thumbnailUrlString urlString: String) {
        let newVideo = Video(context: managedObjectContext)
        
        newVideo.thumbnailUrlString = urlString
        newVideo.title = title
        newVideo.videoID = videoID
        newVideo.createdAt = Date()
        
        
        print("Saving Video")
        
        saveContext()
    }
    
    func saveContext() {
        do {
            try managedObjectContext.save()
        } catch {
            //TODO: add alert instead
            print("There was an error saving")
        }
    } 

调用 saveVideo 后,我的播放/暂停按钮不再起作用,但视频已保存,我可以看到在 Webview 中也调用了相应的函数。我也在为 iOS 14 开发并使用 Xcode 12.3 并且只使用 SwiftUI

标签: core-dataswiftuiwkwebview

解决方案


推荐阅读