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

如何使用iOS WKWebView注入JavaScript回调以检测onclick事件?,javascript,ios,swift,wkwebview,Javascript,Ios,Swift,Wkwebview,我正在使用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="javascri

我正在使用
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)">
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
实施 当我单击webview中的任何按钮时,将在我的
WKNavigationDelegate
上调用此函数:

func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
    // ...?
}
但是当然,
导航
是不透明的,因此不包含有关用户单击的三个按钮中的哪一个的信息

当点击此按钮时,最简单的检测方法是什么? 我想在用户单击“提交”并忽略其他按钮按下时做出响应

我看到了使用
WKUserContentController
处理堆栈溢出的一些其他方法,但它们似乎要求网站调用以下内容:

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

我无法控制此网站,因此无法在其源代码中添加此行,并且我不知道使用
WKWebView

将其插入正确位置的最佳方法。您可以始终在web视图中使用。然后,替换按钮上的事件处理程序(发布消息,然后调用新处理程序中的原始函数),或者在按钮上添加事件处理程序或捕获单击事件并发布消息的祖先元素。(原始事件处理程序也将运行。)


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

您可以使用函数将JS代码注入
WKWebView
。您可以使用下面的JS代码捕获所有
onclick
事件,它只检测单击
submit
按钮。所有原始事件处理程序也将运行-不要担心

document.addEventListener(“单击”),函数(e)
{
e=e | | window.event;
//如果(e.target.value=='Submit')//您可以像这样识别这个按钮,但最好像:
if(e.target.getAttribute('onclick')=='javascript:gotour(3)'
//如果此站点有更多带有onclick=“javascript:gotour(3)”的元素
//if(e.target.value=='Submit'&&e.target.getAttribute('onclick')=='javascript:gotour(3)'
{
console.log(如target.value);
//如果您需要,也可以在此处拨打以下电话:
//window.webkit.messageHandlers.log.postMessage(“提交”);
}
});
//不要在代码中添加下一行!这只是我的演示-按钮需要在我的演示执行此
函数gotour(site){}//不要添加此行!这只是为了我的演示

用户脚本是在文档加载开始时或文档加载完成后注入网页的JS。用户脚本非常强大,因为它们允许客户端自定义网页,允许注入事件监听器,甚至可以用于注入脚本,这些脚本可以反过来调用本机应用程序。下面的代码段创建了一个用户脚本,该脚本在文档加载结束时被注入。用户脚本将添加到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..postMessage()
方法将消息发布到本机应用程序。 这里,“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")

以下是详细的实施:

 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
}
}

谢谢,这很有帮助。你认为你可以展示这些方法的例子吗?我在上面发布了按钮HTML,不幸的是它们没有ID。
 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
}
}