title: iOS WebKit - Determine whether a WebView has completely loaded JS content
body: <p>I'm attempting to parse out some HTML metadata from a third-party URL; however, I don't get the full HTML data until some Javascript scripts are executed in the <code>WKWebView</code>.</p>
  
  <p>So I've been trying to detect when the <code>WKWebView</code> has completely loaded the web page with Javascript but unfortunately I wasn't able to.</p>
  
  <p>Here's what I tried:</p>
  
  <ul>
  <li>I tried using <code>WKUserContentController</code> and handled the protocol method but that didn't work because the protocol method is only executed when it receives a script message not when it's completed.</li>
  <li>I tried adding an observer for <code>WKWebView</code>'s <code>estimatedProgress</code> but <code>estimatedProgress</code> return 1.0 before JS scripts are done loading.</li>
  <li>I tried using <code>WKNavigationDelegate</code> protocol method <code>webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)</code> but it's essentially the same thing as adding an observer.</li>
  <li>I also tried using <code>WKWebView</code>'s <code>evaluateJavaScript</code> method in the <code>observeValue</code> method to check both:
  
  <ul>
  <li><code>document.readyState == \"interactive\"</code></li>
  <li><code>document.readyState == \"completed\"</code></li>
  </ul></li>
  </ul>
  
  <p>but that didn't work either because it's executed way before JS is done loading.</p>
  
  <p><strong>Code</strong></p>
  
  <p>Here's the code of the last approach I attempted and didn't work:</p>
  
  <p><strong>Initializing the <code>WKWebView</code></strong></p>
  
  <pre><code>        let webView = WKWebView(frame: self.view.frame)
          webView.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil)
          webView.load(URLRequest(url: url))
          webView.navigationDelegate = self
          self.view.addSubview(webView)
  </code></pre>
  
  <p><strong>Handling the observer</strong></p>
  
  <pre><code>override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
      if keyPath == "estimatedProgress" {
          if let webView = object as? WKWebView, webView.estimatedProgress &gt; 0.5 {
              print(webView.estimatedProgress)
              webView.evaluateJavaScript("document.readyState == \"interactive\"") { (isLoaded, err) in
                  print(isLoaded)
                  if let loaded = isLoaded as? Bool, loaded == true {
                      print("completely done loading with JS")
                  }
              }
          }
      }
  }
  </code></pre>
  
  <p>The result I get when the <code>evaluateJavaScript</code> method is executed is <code>false</code> because it's executed too early. But I'm trying to let the observer continue until <code>isLoaded</code> is true.</p>