iOS中WKWebView哈希URL失效问题求助(Safari可正常运行)
WKWebView 哈希URL(window.onhashchange)问题修复方案
针对你遇到的WKWebView中哈希URL无法正常触发window.onhashchange事件、点击搜索后显示空白的问题,可通过以下两种方案解决:
一、Swift端配置与导航拦截
通过配置WKWebView基础属性,并拦截哈希导航动作,强制触发哈希变化事件:
import WebKit class WebViewController: UIViewController, WKNavigationDelegate { private var webView: WKWebView! override func viewDidLoad() { super.viewDidLoad() let config = WKWebViewConfiguration() // 启用JavaScript(Web应用核心逻辑依赖此设置) config.preferences.javaScriptEnabled = true // 允许JavaScript打开新窗口(适配部分Web应用的交互逻辑) config.preferences.javaScriptCanOpenWindowsAutomatically = true webView = WKWebView(frame: view.bounds, configuration: config) webView.navigationDelegate = self webView.autoresizingMask = [.flexibleWidth, .flexibleHeight] view.addSubview(webView) // 加载目标URL guard let targetURL = URL(string: "https://www.lefrecce.it/Channels.Website.WEB/#/white-label/MINISITI/?minisitiCallBackId=54276&isRoundTrip=false&lang=en&departureStation=Salerno&arrivalStation=Caserta") else { return } webView.load(URLRequest(url: targetURL)) } // 拦截哈希导航,强制触发hashchange事件 func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { guard let requestURL = navigationAction.request.url, requestURL.fragment != nil else { decisionHandler(.allow) return } decisionHandler(.allow) // 手动触发hashchange事件,确保Web应用捕获到哈希变化 webView.evaluateJavaScript(""" window.dispatchEvent(new HashChangeEvent('hashchange', { oldURL: window.location.href, newURL: '\(requestURL.absoluteString)' })) """) { _, error in if let err = error { print("触发hashchange失败: \(err.localizedDescription)") } } } }
二、注入JavaScript修补哈希事件
部分Web应用依赖history.pushState/replaceState修改哈希(这两个方法不会自动触发hashchange),可注入JS重写这些方法并强制触发事件:
在Swift中,通过WKNavigationDelegate的didFinishNavigation方法注入修复代码:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { let hashFixScript = """ // 保存原生事件处理逻辑 const originalOnHashChange = window.onhashchange; let lastHash = window.location.hash; // 定时检查哈希变化,手动触发事件 setInterval(() => { const currentHash = window.location.hash; if (currentHash !== lastHash) { const hashEvent = new HashChangeEvent('hashchange', { oldURL: window.location.origin + window.location.pathname + lastHash, newURL: window.location.origin + window.location.pathname + currentHash }); // 执行原生事件处理 if (originalOnHashChange) originalOnHashChange.call(window, hashEvent); // 触发全局事件 window.dispatchEvent(hashEvent); lastHash = currentHash; } }, 100); // 重写pushState,触发hashchange const originalPushState = history.pushState; history.pushState = function(state, title, url) { originalPushState.call(this, state, title, url); const hashEvent = new HashChangeEvent('hashchange', { oldURL: window.location.href, newURL: window.location.origin + window.location.pathname + url }); window.dispatchEvent(hashEvent); }; // 重写replaceState,触发hashchange const originalReplaceState = history.replaceState; history.replaceState = function(state, title, url) { originalReplaceState.call(this, state, title, url); const hashEvent = new HashChangeEvent('hashchange', { oldURL: window.location.href, newURL: window.location.origin + window.location.pathname + url }); window.dispatchEvent(hashEvent); }; """ webView.evaluateJavaScript(hashFixScript) { _, error in if let err = error { print("注入哈希修复脚本失败: \(err.localizedDescription)") } else { print("哈希修复脚本注入成功") } } }
关键注意事项
- 必须确保WKWebView的
javaScriptEnabled为true,否则所有Web交互逻辑都会失效; - 定时检查的间隔(示例中为100ms)可根据Web应用的响应速度调整,间隔越小响应越及时,但会增加少量性能开销;
- 若Web应用使用Vue、React等前端框架的哈希路由,上述方案可确保框架路由监听器捕获到哈希变化,正常渲染页面。
内容的提问来源于stack exchange,提问作者Daniele B
相关产品推荐
相关产品推荐

