在 WKWebView 上添加点击事件监听器不起作用
Adding a click event listener on WKWebView not working
我正在开发一个使用 WKWebView 的应用程序,我试图在用户单击网页上的按钮时添加一个事件侦听器。该按钮没有 ID,所以我正在使用 class。
我可以使用检查控制台在 chrome 上正确设置它:
对于我的 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 后添加代码后,Everything 开始工作。我仍然不知道为什么。
这是目前完整扩展的代码:
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, elementType: ElementType, 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: { [=10=].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)
}
}
}
我正在开发一个使用 WKWebView 的应用程序,我试图在用户单击网页上的按钮时添加一个事件侦听器。该按钮没有 ID,所以我正在使用 class。
我可以使用检查控制台在 chrome 上正确设置它:
对于我的 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 后添加代码后,Everything 开始工作。我仍然不知道为什么。
这是目前完整扩展的代码:
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, elementType: ElementType, 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: { [=10=].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)
}
}
}