Notes on listening to location changes in WKWebView

Boon aka Hwee-Boon Yar August 24, 2021
Source

WKNavigationDelegate is useful for tracking when user navigates to a different URL with functions such as webView(_:,decidePolicyFor:,decisionHandler:). But if the site uses HTML History API to the location (common with React and friends), it doesn't pick it up. Here's how to support it:

  1. This JavaScript to dispatch a message to the WKWebView instance's message handler:

// So we can detect when sites use History API to generate the page location. Especially common with React and similar frameworks ;(function() { var pushState = history.pushState; var replaceState = history.replaceState;

history.pushState = function() { pushState.apply(history, arguments); window.dispatchEvent(new Event('locationchange')); };

history.replaceState = function() { replaceState.apply(history, arguments); window.dispatchEvent(new Event('locationchange')); };

window.addEventListener('popstate', function() { window.dispatchEvent(new Event('locationchange')) }); })();

window.addEventListener('locationchange', function(){ webkit.messageHandlers.locationChanged.postMessage(window.location.href) })

  1. Inject the JavaScript above is to install a user script:

let webViewConfig = WKWebViewConfiguration() let userScript = WKUserScript(source: js, injectionTime: .atDocumentStart, forMainFrameOnly: false) webViewConfig.userContentController.addUserScript(userScript) //Install handler (below) let webView = WKWebView(frame: .zero, configuration: config)

  1. Specify the message handler:

webViewConfig.userContentController.add(messageHandler, name: "locationChanged")

  1. Handle the message, getting the URL:

extension SomeClass: WKScriptMessageHandler { func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { //get the URL from message or just from webView.url } }

Thanks to the suggestion from @hishnash.

Discussion in the ATmosphere

Loading comments...