如何让WKWebView完全拦截超链接且正常加载显示内容?
WKWebView 全场景链接拦截问题解析与解决
问题现象
使用loadHTMLString加载本地HTML内容时:
- 仅拦截
.linkActivated类型导航时,WebView正常显示,用户点击链接不会跳转,代码如下:
extension AuthorizationContentView: WKNavigationDelegate { func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { if navigationAction.navigationType == .linkActivated { decisionHandler(.cancel) } else { decisionHandler(.allow) } } }
- 若直接在代理方法中返回
decisionHandler(.cancel),WebView无法显示内容,代码如下:
extension AuthorizationContentView: WKNavigationDelegate { func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { decisionHandler(.cancel) return } }
补充加载HTML的代码:
func setupWebView(content: String) { let supportDarkCSS = "<style>:root { color-scheme: light dark; }</style>" contentStackView.removeAllArrangedSubviews() webView.loadHTMLString(content + supportDarkCSS, baseURL: nil) contentStackView.addArrangedSubview(webView) }
问题原因
直接返回.cancel会拦截所有导航动作,包括loadHTMLString触发的初始渲染导航——这个导航的navigationType为.other,且请求URL为空,被拦截后WebView无法完成HTML内容的加载与渲染。
另外,.linkActivated仅覆盖用户直接点击带href属性链接的场景,像JS触发的用户交互跳转、表单提交等场景,其navigationType并非.linkActivated,需要更全面的判断逻辑。
解决方案
方案1(iOS 13+ 推荐)
利用isUserInitiated属性判断是否为用户主动触发的导航,同时允许初始加载:
extension AuthorizationContentView: WKNavigationDelegate { func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { // 允许初始加载及非用户主动触发的导航(如页面内部资源加载) if navigationAction.request.url == nil || !navigationAction.isUserInitiated { decisionHandler(.allow) } else { // 拦截所有用户主动触发的跳转(含点击链接、JS交互跳转等) decisionHandler(.cancel) // 如需处理跳转链接,可在此获取URL做后续操作 if let targetUrl = navigationAction.request.url { // 示例:打开系统浏览器 // UIApplication.shared.open(targetUrl) } } } }
方案2(兼容iOS 13以下)
通过判断navigationType覆盖常见用户跳转场景,同时放行初始加载:
extension AuthorizationContentView: WKNavigationDelegate { func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { // 放行HTML初始加载请求 if navigationAction.request.url == nil && navigationAction.navigationType == .other { decisionHandler(.allow) return } // 拦截所有用户可能触发的跳转类型 let interceptTypes: [WKNavigationType] = [.linkActivated, .formSubmitted, .backForward, .reload] if interceptTypes.contains(navigationAction.navigationType) { decisionHandler(.cancel) // 处理目标链接逻辑 if let targetUrl = navigationAction.request.url { // ... } } else { decisionHandler(.allow) } } }
内容的提问来源于stack exchange,提问作者Morozov
相关产品推荐
相关产品推荐

