无法在WKWebView上添加点击事件监听器

问题描述

我正在开发一个使用WKWebView的应用程序,并且当用户单击网页上的按钮时,我试图添加事件侦听器。该按钮没有ID,所以我正在上课。

我可以使用检查控制台在chrome上正确设置它:

enter image description here

对于我的Swift开发,我尝试在WKWebView扩展内添加一个函数,以便可以像这样重用它:

extension WKWebView {
    /// Adds a event listener that will be call on WKScriptMessageHandler - didReceiveMessage
    /// - Parameters:
    ///   - elementID: The name of the element
    ///   - callbackID: The ID for the callback
    ///   - elementType: The type of element to get
    ///   - completion: Callback triggered went script has been appended to WKWebView
    //NOT WORKING
    func addEventListener(id: String,callbackID: String,elementType: ElementType,handler: WKScriptMessageHandler,completion: ((Error?)->Void)?) {
        let scriptString: String
        
        switch elementType {
        case .id:
            scriptString = """
                document.getElementById('\(id)').addEventListener('click',function(){
                    webkit.messageHandlers.refreshWebPage.postMessage("status":"ok");
                });
                """
        case .class:
            scriptString = """
                document.getElementsByClassName('\(id)')[0].addEventListener('click',function(){
                    webkit.messageHandlers.refreshWebPage.postMessage("status":"ok");
                });
                """
        }
        
        let script = WKUserScript(source: scriptString,injectionTime: .atDocumentStart,forMainFrameOnly: false)
        configuration.userContentController.addUserScript(script)
        configuration.userContentController.add(handler,name: "postMessage")
    }
} 

然后,在包含WKWebView的UIViewController上:

//MARK: WKNavigationDelegate implementation
extension ArtpadWebViewController: WKNavigationDelegate {
    func webView(_ webView: WKWebView,didFinish navigation: WKNavigation!) {
        webView.addEventListener(id: "top_left_menu",callbackID: backCallbackID,elementType: .class,handler: self,completion: nil)
    }
}

//MARK: WKScriptMessageHandler implementation
extension ArtpadWebViewController: WKScriptMessageHandler {
    func userContentController(_ userContentController: WKUserContentController,didReceive message: WKScriptMessage) {
        print("HO!")
    }
}

但是,未调用WKScriptMessageHandler函数...我一直在尝试找到的不同解决方案,但没有一个起作用。我想念什么?

谢谢

解决方法

由于某种原因,在评估该javascript后添加代码后,一切都开始工作。我仍然不知道为什么。

这是到目前为止完整扩展的代码:

extension WKWebView {
    /// Type of HTML element to get from DOM
    enum ElementType {
        /// ID Element
        case id
        /// Class element
        case `class`
    }
    
    /// List of errors for WKWebView injection
    enum InjectionError: Error {
        /// The Listener is already added
        case listenerAlreadyAdded
    }
    
    /// Cahnges the CSS Visibiltiy
    /// - Parameters:
    ///   - elementID: The name of the element
    ///   - isVisible: Wether or not is visible
    ///   - elementType: The type of element to get
    ///   - completion: Callback triggered went script has been appended to WKWebView
    func changeCSSVisibility(elementID: String,isVisible: Bool,elementType: ElementType,completion: ((Error?)->Void)?) {
        let script: String
        
        switch elementType {
        case .id:
            script = "document.getElementById('\(elementID)').style.visibility = \(isVisible ? "'visible'":"'hidden'");"
        case .class:
        script =
            """
            [].forEach.call(document.querySelectorAll('.\(elementID)'),function (el) {
              el.style.visibility = \(isVisible ? "'visible'":"'hidden'");
            });
            """
        }
        
        evaluateJavaScript(script,completionHandler: { (result,error) in
            completion?(error)
        })
    }
    
    /// Adds a event listener that will be call on WKScriptMessageHandler - didReceiveMessage
    /// - Parameters:
    ///   - elementID: The name of the element
    ///   - callbackID: The ID for the callback
    ///   - elementType: The type of element to get
    ///   - completion: Callback triggered went script has been appended to WKWebView
    func addEventListener(elementID: String,callbackID: String,handler: WKScriptMessageHandler,completion: ((Error?)->Void)?) {
        let element: String
        
        switch elementType {
        case .id:
            element = "document.getElementById('\(elementID)')"
        case .class:
            element = "document.getElementsByClassName('\(elementID)')[0]"
        }
        
        let scriptString = """
            function callback () {
                console.log('\(callbackID) clicked!')
                window.webkit.messageHandlers.\(callbackID).postMessage({
                    message: 'WKWebView-onClickListener-\(callbackID)'
                });
            }

            \(element).addEventListener('click',callback);
            """
        
        if configuration.userContentController.userScripts.first(where: { $0.source == scriptString }) == nil {
            evaluateJavaScript(scriptString) { [weak self] (result,error) -> Void in
                guard let self = self else { return }
                
                if let error = error {
                    completion?(error)
                } else {
                    self.configuration.userContentController.removeScriptMessageHandler(forName: callbackID)
                    self.configuration.userContentController.add(handler,name: callbackID)
                    self.configuration.userContentController.addUserScript(WKUserScript(source: scriptString,injectionTime: .atDocumentEnd,forMainFrameOnly: false))
                }
            }
        } else {
            completion?(InjectionError.listenerAlreadyAdded)
        }
    }
}