如何使用iOS WKWebView注入JavaScript回调来检测onclick事件



我正在使用WKWebView来显示一个包含三个按钮的HTML网站。我想在点击特定按钮时在本地应用程序中运行一些Swift代码。

关于HTML

三个按钮看起来像这样:

<input type="button" value="Edit Info" class="button" onclick="javascript:GotoURL(1)">
<input type="button" value="Start Over" class="button" onclick="javascript:GotoURL(2)">
<input type="button" value="Submit" class="button" onclick="javascript:GotoURL(3)">

他们调用的GotoURL函数如下所示:

function GotoURL(site)
{
if (site == '1')
document.myWebForm.action = 'Controller?op=editinfo';
if (site == '2')
document.myWebForm.action = 'Controller?op=reset';
if (site == '3')
document.myWebForm.action = 'Controller?op=csrupdate';
document.myWebForm.submit();
}

当前WKWebView实现

当我点击网络视图中的任何按钮时,这个函数会在我的WKNavigationDelegate:上调用

func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
// ...?
}

当然,navigation是不透明的,因此不包含关于用户点击了三个按钮中的哪一个的信息。

当点击这个按钮时,最简单的检测方法是什么

当用户单击Submit并忽略其他按钮按下时,我希望做出响应。

我在使用WKUserContentController的Stack Overflow上看到了一些其他方法,但它们似乎需要网站调用以下内容:

window.webkit.messageHandlers.log.postMessage("submit");

我不控制这个网站,所以我不能在它的源代码中添加这一行,而且我不知道使用WKWebView将它注入正确位置的最佳方法。

用户脚本是JS,您可以在文档加载开始时或文档加载完成后将其注入到网页中。用户脚本非常强大,因为它们允许客户端自定义网页,允许注入事件侦听器,甚至可以用于注入脚本,这些脚本可以反过来调用回Native应用程序。下面的代码片段创建了一个用户脚本,该脚本在文档加载结束时注入。用户脚本被添加到WKUserContentController实例中,该实例是WKWebViewConfiguration对象上的属性。

// Create WKWebViewConfiguration instance
var webCfg:WKWebViewConfiguration = WKWebViewConfiguration()
// Setup WKUserContentController instance for injecting user script
var userController:WKUserContentController = WKUserContentController()
// Get script that's to be injected into the document
let js:String = buttonClickEventTriggeredScriptToAddToDocument()
// Specify when and where and what user script needs to be injected into the web document
var userScript:WKUserScript =  WKUserScript(source: js, 
injectionTime: WKUserScriptInjectionTime.atDocumentEnd,
forMainFrameOnly: false)
// Add the user script to the WKUserContentController instance
userController.addUserScript(userScript)
// Configure the WKWebViewConfiguration instance with the WKUserContentController
webCfg.userContentController = userController;

您的网页可以通过window.webkit.messageHandlers.<name>.postMessage (<message body>)方法将消息发布到您的本地应用程序。在这里,"name"是返回的消息的名称。JS可以将任何JS对象作为消息体发布,JS对象将自动映射到相应的Swift原生对象。当Id为"ClickMeButton"的按钮上发生按钮单击事件时,以下JS代码片段会返回一条消息。

var button = document.getElementById("clickMeButton");
button.addEventListener("click", function() {
varmessageToPost = {'ButtonId':'clickMeButton'};
window.webkit.messageHandlers.buttonClicked.postMessage(messageToPost);
},false);

为了接收网页发布的消息,您的本地应用程序需要实现WKScriptMessageHandler协议。该协议定义了一个所需的方法。可以查询回调中返回的WKScriptMessage实例,以获取有关返回消息的详细信息。

func userContentController(userContentController: WKUserContentController,
didReceiveScriptMessage message: WKScriptMessage) {
if let messageBody:NSDictionary= message.body as? NSDictionary{
// Do stuff with messageBody
}
}

最后,实现WKScriptMessageHandler协议的本机类需要将自己注册为WKWebView的消息处理程序,如下所示:

// Add a script message handler for receiving  "buttonClicked" event notifications posted 
// from the JS document
userController.addScriptMessageHandler(self, name: "buttonClicked")

您始终可以在web视图中使用evaluateJavaScript(_:)注入源代码。从那里,可以替换按钮上的事件处理程序(发布消息,然后在新处理程序中调用原始函数(,也可以在按钮上添加事件处理程序或捕获单击事件并发布消息的祖先元素。(原始事件处理程序也将运行。(

document.getElementById("submit-button").addEventListener("click", function () {
   window.webkit.messageHandlers.log.postMessage("submit");
});

如果按钮没有ID,您可以在文档上添加一个处理程序,用于捕获所有(冒泡(点击事件,然后根据事件目标发布消息(使用按钮的文本或位置作为决定因素(。

您可以使用evaluateJavaScript()函数向WKWebView注入JS代码。您可以使用以下JS代码捕获所有onclick事件,这些代码只检测点击submit按钮。所有原始事件处理程序也将运行-别担心!

document.addEventListener("click", function(e)
{
e = e || window.event;
//if(e.target.value == 'Submit') //you can identify this button like this, but better like:
if(e.target.getAttribute('onclick') == 'javascript:GotoURL(3)')
//if this site has more elements with onclick="javascript:GotoURL(3)"
//if(e.target.value == 'Submit' && e.target.getAttribute('onclick') == 'javascript:GotoURL(3)')
{
console.log(e.target.value);
//if you need then you can call the following line on this place too:
//window.webkit.messageHandlers.log.postMessage("submit");
}
});
//DO NOT add the next line in your code! It is only for my demo - buttons need this in my demo for execution
function GotoURL(site){}//DO NOT add this line! It is only for my demo!
<input type="button" value="Edit Info" class="button" onclick="javascript:GotoURL(1)">
<input type="button" value="Start Over" class="button" onclick="javascript:GotoURL(2)">
<input type="button" value="Submit" class="button" onclick="javascript:GotoURL(3)">

下面是详细的实现:

var webView: WKWebView?
var webConfig:WKWebViewConfiguration {
get {
let webCfg:WKWebViewConfiguration = WKWebViewConfiguration()
let userController:WKUserContentController = WKUserContentController()
userController.add(self, name: "submit")
let js:String = buttonClickEventTriggered()
let userScript:WKUserScript =  WKUserScript(source: js, injectionTime:WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: false)
userController.addUserScript(userScript)
webCfg.userContentController = userController;
return webCfg;
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.webView = WKWebView(frame: self.view.frame, configuration: webConfig)
self.webView!.navigationDelegate = self
self.view = webView!
let url = URL(string:"your URL here")
let req = NSURLRequest(url:url! as URL)
self.webView!.load(req as URLRequest)
}
func buttonClickEventTriggered() ->String{
let script:String = "document.getElementById('your button id here').addEventListener('click', function () {window.webkit.messageHandlers.submit.postMessage('submited');});"//Make sure you have mapped the name correctly under userController.add
return script;
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print("Sucessss")
if(message.name == "submit") {
print("It does ! (message.body)")
// Your code goes here
}
}

最新更新