I am using a WKWebView inside a UIViewController's view to display a webpage hosted on a server using a url endpoint. The webpage uses Reactjs. That is all the information I have about the webpage. The code creates a webview and inserts the webview as subview of the controllers view.
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)
The webpage loads fine and also the controller acts as the delegate of the webview and receives the messages for the same. Now I also implement a WKWebViewWrapper class which conforms to WKScriptMessageHandler. This class can then receive messages from webkit object which is created by the WKWebView behing the scenes. The implementation for the same is as below
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)
}
}
}
}
}
The setUpPlayerAndEventDelegation() method is the most important part. Here for the controller object which is of type WKUserContentcontroller adds message handlers using its add(: , name:) method. According to documentation this method adds a messageHandler of the name parameter to the webkit object. Whenver the messsage handler is triggered, the WKScriptMessageHandler's userContentController( userContentController: WKUserContentController, didReceive message: WKScriptMessage) method is called with useful parameters. Then I inject javascript into the webpage using evaluateJavaScript method of webview which is as below
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)) });
}
It fetches elements with the given class. Then I iterate over the array to add event listener for HTML event 'onClick' for each element. For events listener I add an anonymous function to trigger the previously registered message handler on the webkit. This script is executed properly as I don't get error in the completion block of the evaluateJavaScript method. So I can be sure now that when a button onClick HTML event occurs the annonymous function will execute, which in turn will postMessage for the messageHandler on the webkit object.
Now I call the WKWebViewWrapper's setUpPlayerAndEventDelegation() method from WKWebViewDelegate method webView(_ webView: WKWebView, didFinish navigation: WKNavigation!), where I can be sure that all the HTML elements are loaded by comapring WKNavigation objects.
The flow executes and after the Page loads and I click any buttons the events are not observed by my script message handler i.e the WKWebViewWrapper class. The method userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) is not fired at all.
Is there something that I am missing here?. I am not good at Javascript. Please do let me know if Reactjs needs some different script to and event listener to button elements. I have reffered this tutorial.
PS: If we add the similar script to output console messages on a webbrowser which has loaded the page, it works fine.
from WKScriptMessageHandler won't Listen to 'onclick' or 'click' event on a button element on a webpage. The web page is developed using Reactjs
Here's a link to our share buttons: https://shareaholic.com/pub...
ReplyDeleteYou can add all the buttons you need, and have them appear on the top and/or bottom of posts.
For example, The Social Media Hat uses our buttons above their content and at the end of their posts. See how our buttons look on their site:
http://www.thesocialmediaha...
Of course, you can customize your buttons in a variety of ways in your Settings.
If you have any technical issues, feel free to reference our support center (http://support.shareaholic.... but if you can't find what you're looking for, submit a request and we'll be glad to help.