{
"$type": "site.standard.document",
"description": "WKNavigationDelegate is useful for tracking when user navigates to a different URL with functions such as webView :,decidePolicyFor:,decisionHandler:",
"path": "/notes-wkweb-view-location-change-history-aoi/",
"publishedAt": "2021-08-24T07:12:00.000Z",
"site": "at://did:plc:bryys25pc2fnagnyxqgsglhd/site.standard.publication/3mn26bjkkmh23",
"tags": [
"iOS Development",
"macOS Development",
"Swift",
"Techniques"
],
"textContent": "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:\n\n1. This JavaScript to dispatch a message to the WKWebView instance's message handler:\n\n // So we can detect when sites use History API to generate the page location. Especially common with React and similar frameworks\n ;(function() {\n var pushState = history.pushState;\n var replaceState = history.replaceState;\n\n history.pushState = function() {\n pushState.apply(history, arguments);\n window.dispatchEvent(new Event('locationchange'));\n };\n\n history.replaceState = function() {\n replaceState.apply(history, arguments);\n window.dispatchEvent(new Event('locationchange'));\n };\n\n window.addEventListener('popstate', function() {\n window.dispatchEvent(new Event('locationchange'))\n });\n })();\n\n window.addEventListener('locationchange', function(){\n webkit.messageHandlers.locationChanged.postMessage(window.location.href)\n })\n\n2. Inject the JavaScript above is to install a user script:\n\nlet webViewConfig = WKWebViewConfiguration()\nlet userScript = WKUserScript(source: js, injectionTime: .atDocumentStart, forMainFrameOnly: false)\nwebViewConfig.userContentController.addUserScript(userScript)\n//Install handler (below)\nlet webView = WKWebView(frame: .zero, configuration: config) \n\n3. Specify the message handler:\n\nwebViewConfig.userContentController.add(messageHandler, name: \"locationChanged\")\n\n4. Handle the message, getting the URL:\n\n extension SomeClass: WKScriptMessageHandler {\n func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {\n //get the URL from `message` or just from `webView.url`\n }\n }\n\nThanks to the suggestion from @hishnash.",
"title": "Notes on listening to location changes in WKWebView"
}