let requestObj = URL(string:urlString)! let preferences = WKPreferences() preferences.javaScriptEnabled = true let configuration = WKWebViewConfiguration() configuration.preferences = preferences webViewWK = WKWebView(frame: .zero,configuration: configuration) webViewWK.navigationDelegate = self _ = webViewWK.load(requestObj) webViewwrapper = WKWebViewWrapper(forWebView: webViewWK)
网页加载正常,控制器也充当webview的委托,并接收相同的消息.现在我还实现了一个符合WKScriptMessageHandler的WKWebViewWrapper类.然后,此类可以从Webkit对象接收消息,该消息由WKWebView创建的场景创建.实现方法如下
class WKWebViewWrapper : NSObject,WKScriptMessageHandler{ var wkWebView : WKWebView let eventNames = ["buttonClick"] var eventFunctions: Dictionary<String,(String) -> Void> = [:] let controller: WKUserContentController init(forWebView webView : WKWebView){ wkWebView = webView controller = WKUserContentController() super.init() } func userContentController(_ userContentController: WKUserContentController,didReceive message: WKScriptMessage) { if let contentBody = message.body as? String { if let eventFunction = eventFunctions[message.name]{ print("Detected javascript event") } } } func setUpPlayerAndEventDelegation(){ wkWebView.configuration.userContentController = controller for eventname in eventNames { controller.add(self,name: eventname) eventFunctions[eventname] = { _ in } wkWebView.evaluateJavaScript("var elements = document.getElementsByClassName('btn button_btn button_primary button_md button_block'); for (var i = 0 ; i < elements.length; i++) { elements[i].addEventListener('onClick',function(){ window.webkit.messageHandlers.\(eventname).postMessage(JSON.stringify(isSuccess)) }); }") { any,error in if let error = error { print("EvaluateJavaScript Error:",error) } if let any = any { print("EvaluateJavaScript anything:",any) } } } }
}
setUpPlayerAndEventDelegation()方法是最重要的部分.这里为WKUserContentController类型的控制器对象使用其add(:,name :)方法添加消息处理程序.根据文档,此方法将name参数的messageHandler添加到webkit对象.当触发消息处理程序时,将使用有用的参数调用WKScriptMessageHandler的userContentController(userContentController:WKUserContentController,didReceive message:WKScriptMessage)方法.然后我使用webview的evaluateJavaScript方法将javascript注入网页,如下所示
var elements = document.getElementsByClassName('btn button_btn button_primary button_md button_block'); for (var i = 0 ; i < elements.length; i++) { elements[i].addEventListener('onClick',function(){ window.webkit.messageHandlers.\(eventname).postMessage(JSON.stringify(true)) }); }
它使用给定的类获取元素.然后我遍历数组,为每个元素的HTML事件’onClick’添加事件监听器.对于事件监听器,我添加了一个匿名函数来触发webkit上先前注册的消息处理程序.这个脚本正确执行,因为我没有在evaluateJavaScript方法的完成块中得到错误.所以我现在可以肯定,当一个按钮onClick HTML事件发生时,将执行匿名函数,而后者将为webkit对象上的messageHandler执行postMessage.
现在我从WKWebViewDelegate方法webView(_ webView:WKWebView,didFinish navigation:WKNavigation!)调用WKWebViewWrapper的setUpPlayerAndEventDelegation()方法,在那里我可以确保通过comapring WKNavigation对象来加载所有HTML元素.
流程执行,在页面加载后,我点击任何按钮,我的脚本消息处理程序,即WKWebViewWrapper类,都没有观察到事件.方法userContentController(_ userContentController:WKUserContentController,didReceive message:WKScriptMessage)根本没有被触发.
这里有什么我想念的吗?我不擅长Javascript.如果Reactjs需要一些不同的脚本和事件监听器的按钮元素,请告诉我. I have reffered this tutorial.
解决方法
WKWebViewConfiguration仅在首次初始化Web视图时使用.创建后,您无法使用此类更改Web视图的配置.
因此,通常您应该在创建Web视图之前完全设置WKUserContentController.
// First,create custom configuration with user script let userController = WKUserContentController() let scalingScriptString = "var Meta = document.createElement('Meta'); Meta.setAttribute('name','viewport'); Meta.setAttribute('content','width=device-width'); document.getElementsByTagName('head')[0].appendChild(Meta);"; let scalingScript = WKUserScript(source: scalingScriptString,injectionTime: .atDocumentStart,forMainFrameOnly: true) userController.addUserScript(scalingScript) let configurations = WKWebViewConfiguration() configurations.userContentController = userController // MUST set controller in configurations before creating webview // Now,use that configuration to create the webview webView = WKWebView(frame: .zero,configuration: configurations)