Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I detect when an element is visible after loading website in WKWebView?

I am trying to load a transit website so I can scrape the stop times for a given stop. After I load the url, the stop times are loaded in a bit later dynamically through javascript. My goal is to detect the presence of elements with a class of "stop-time". If these elements are present in the html I can then parse the html. But before I can parse the html I have to wait for these elements with class of "stop-time" to appear. I read through a bunch of other SO questions but I couldn't quite piece it together. I am implementing the didReceive message function but I'm not really sure how to load in the javascript I need to detect the presence of the elements (elements with class of "stop-time"). I successfully injected some javascript to prevent the location permission popup from showing.

override func viewDidLoad() {
    super.viewDidLoad()

    let contentController = WKUserContentController()
    let scriptSource = "navigator.geolocation.getCurrentPosition = function(success, error, options) {}; navigator.geolocation.watchPosition = function(success, error, options) {}; navigator.geolocation.clearWatch = function(id) {};"
    let script = WKUserScript(source: scriptSource, injectionTime: .atDocumentStart, forMainFrameOnly: true)
    contentController.addUserScript(script)

    let config = WKWebViewConfiguration()
    config.userContentController = contentController

    webView = WKWebView(frame: .zero, configuration: config)
    self.view = self.webView!

    loadStopTimes("https://www.website.com/stop/1000")
}

func loadStopTimes(_ busUrl: String) {
    let urlString = busUrl
    let url = URL(string: urlString)!
    let urlRequest = URLRequest(url: url)
    webView?.load(urlRequest)
}

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    if(message.name == "stopTimesLoaded") {
        // stop times now present so take the html and parse the stop times
    }
}
like image 481
user3614030 Avatar asked Jul 27 '18 03:07

user3614030


People also ask

How do I know if WKWebView is loaded Swift?

To check if your WKWebView has loaded easily implement the following method: import WebKit import UIKit class ViewController: UIViewController, WKNavigationDelegate { let webView = WKWebView() func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)

Does iOS have webView?

WKWebView replaces the UIWebView class in iOS 8 and later, and it replaces the WebView class in macOS 10.10 and later. Embed a WKWebView object programmatically into your view hierarchy, or add it using Interface Builder.

What is webView swift?

WebView can be defined as an object which can display the interactive web content and load HTML strings within the iOS application for an in-app browser. It is an instance of the WKWebView class, which inherits the UIView class.


1 Answers

First of all You need to inject next script to detect appearence of elements via mutations observer:

var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      console.log('mutation.type = ' + mutation.type);
      for (var i = 0; i < mutation.addedNodes.length; i++) {
        var node = mutation.addedNodes[i];
        if (node.nodeType == Node.ELEMENT_NODE && node.className == 'stop-time') {
            var content = node.textContent;
            console.log('  "' + content + '" added');
            window.webkit.messageHandlers.stopTimesLoaded.postMessage({ data: content });
        }
      }
    });
  });
observer.observe(document, { childList: true, subtree: true });

Then You need to subscribe for event 'stopTimesLoaded':

contentController.add(self, name: "stopTimesLoaded")

And finally add code to process data in

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)
like image 70
HereTrix Avatar answered Oct 05 '22 22:10

HereTrix