iosswiftuiwebviewwkwebviewevaluatejavascript

nested stringByEvaluatingJavaScript in UIWebview migrate to WKWebview


In UIWebview implementation I had something like:-

if let pageBody = webView?.stringByEvaluatingJavaScript(from: "document.body.innerHTML")  {
           if pageBody.contains("xyz") {
               return webView?.stringByEvaluatingJavaScript(from:
                   "document.getElementById('xyz').innerHTML")
           }
        }

I am trying to migrate this to WKWebview:-

I did something like this but the return value gets lost in the nested completion handlers:-

wkWebView?.evaluateJavaScript("document.body.innerHTML", completionHandler: { (pageBody, nil) in
                if let pBody = (pageBody as? String)?.contains("xyz"), pBody {
                    wkWebView?.evaluateJavaScript("document.getElementById('xyz').innerHTML", completionHandler: { (result, error) in
                        resultString = result as? String
                    })
                }
            })
return resultString

Solution

  • evaluateJavaScript is run asynchronously (unlike stringByEvaluatingJavaScript which will wait until the javascript has been evaluated and return the result), so resultString hasn't been set by the time you return it. You will need to organize your code so that the result of javascript is used after the completion handler has been run. Something like this:

    func getElementXYZ(_ completionHandler: @escaping (String?) -> Void) {
        wkWebView?.evaluateJavaScript("document.body.innerHTML") { (pageBody, nil) in
            if let pBody = (pageBody as? String)?.contains("xyz"), pBody {
                wkWebView?.evaluateJavaScript("document.getElementById('xyz').innerHTML") { (result, error) in
                    completionHandler(result as? String)
                }
            }
        }
    }
    

    And to call the function:

    self.getElementXYZ { result in
        //Do something with the result here
    }