简体   繁体   English

如何在 WKWebView Swift 中运行 javascript 命令

[英]How do I run a javascript command in WKWebView Swift

I am trying to run a javascript command that works if I run it in the console on the web.我正在尝试运行 javascript 命令,如果我在 web 上的控制台中运行它,该命令就可以工作。 I have tried doing the code below, but I keep getting nil as my response.我试过做下面的代码,但我的回答一直是 nil 。

webView.evaluateJavaScript("command") { (result, error) in
     if error == nil {
          print(result)
     } else {
          print(error)
     }
}

Here is the code to inject javascript code in your WKWebView这是在 WKWebView 中注入 javascript 代码的代码

let wkUScript = WKUserScript(source: "your javascript command",
                             injectionTime: .atDocumentEnd,
                             forMainFrameOnly: true)
let wkUController = WKUserContentController()
wkUController.addUserScript(wkUScript)

let wkWebConfig = WKWebViewConfiguration()
wkWebConfig.userContentController = wkUController

let webView = WKWebView(frame: CGRect(x: 0, y: 0, width: 400, height: 400), configuration: wkWebConfig)

In case if your webview loads a part of body(or whole html body) additionally, then you won't have desired results by evaluating your javascript inside of method:如果您的 webview 加载了身体的一部分(或整个 html 身体),那么通过在方法内评估您的 javascript 将不会获得所需的结果:

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) 

Reason for this is because "didFinish" method is called once navigation is done inside of webview, but not strictly after loading whole content inside of webView which could be in states:这样做的原因是,一旦在 webview 内部完成导航,就会调用“didFinish”方法,但不是严格在 webView 内部加载全部内容后调用,这可能处于以下状态:

  1. state: empty body state:空体
  2. state: some loading state:一些加载
  3. state: javascript framework did his job and inserted app-body inside state:javascript 框架完成了他的工作并在里面插入了 app-body
  4. state: body has content state:正文有内容

"didFinish" is called in state 1. You can wait for some time with DispatchQueue.main.asyncAfter and then do the.evaluateJavascript but it will make webView makes changes in front of user(ugly per my opinion...)在 state 1 中调用了“didFinish”。您可以使用 DispatchQueue.main.asyncAfter 等待一段时间,然后执行 .evaluateJavascript 但它会使 webView 在用户面前进行更改(我认为这很丑...)

My proposal would be this extension:我的建议是这个扩展:

extension WKWebView {

// it re-execute javascript in cases when body is attached additionally on the html by some inner javascript framework
// it tries around 50 times maximum in time range of 10 sec
// if body is not loaded in 10 secs, this won't work
func rexecuteJavascript(tryouts: Int = 0, script: String) {
    self.evaluateJavaScript(script, completionHandler: { (result: Any?, error: Error?) in
        if let _ = error, tryouts < 50 {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
                return self.rexecuteJavascript(tryouts: tryouts + 1, script: script)
            }
        }
    })
}

} }

It works perfectly for me because body of webview gets populated in around 2-3 secs after "didFinish", and I use this to execute my javascript on fully loaded body:它非常适合我,因为 webview 的主体在“didFinish”后大约 2-3 秒内被填充,我使用它在满载的主体上执行我的 javascript:

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    let removeFooterScript = "document.getElementsByClassName('global-footer')[0].style.display='none';"

    webView.rexecuteJavascript(script: removeFooterScript)
}

Cheers!干杯!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM