Swift中WKWebView无法打开指定URL,跳转至Safari的问题排查
问题分析与修复方案
嘿,我一眼就瞅到问题的根源了!你添加的decidePolicyFor代理方法逻辑完全写反啦,这才导致所有http/https链接都跳去Safari,根本没法在WKWebView里加载。
问题出在哪?
看你当前的代理代码:只要检测到链接是http://或https://开头,你就调用decisionHandler(.cancel)取消WebView的加载,然后用UIApplication.shared.open把链接丢给系统浏览器打开——这可不就是强制跳Safari嘛!完全违背了你想要在WebView内打开页面的需求。
修复后的代理代码
把逻辑调转过来:我们要允许所有http/https链接在WKWebView内加载,只有遇到非http/https的自定义URL Scheme(比如app://、mailto:这类)时,再考虑用外部方式处理。修改后的代码如下:
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { guard let url = navigationAction.request.url else { decisionHandler(.allow) return } let urlString = url.description.lowercased() // 核心调整:允许http/https链接在WebView内加载 if urlString.starts(with: "http://") || urlString.starts(with: "https://") { decisionHandler(.allow) } else { // 处理自定义URL Scheme(比如唤起其他App、发送邮件等) if UIApplication.shared.canOpenURL(url) { UIApplication.shared.open(url, options: [:], completionHandler: nil) decisionHandler(.cancel) // 取消WebView加载,交给外部处理 } else { decisionHandler(.allow) // 不支持的Scheme就交给WebView处理(大概率会失败,但留个兜底) } } }
进阶优化(可选)
如果你想要更精细的控制——比如只有你指定的域名(比如yyy.com)留在WebView内,其他域名跳Safari,可以再加一层域名校验:
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { guard let url = navigationAction.request.url else { decisionHandler(.allow) return } let urlString = url.description.lowercased() if urlString.starts(with: "http://") || urlString.starts(with: "https://") { // 只允许yyy.com相关的链接在WebView内加载 if urlString.contains("yyy.com") { decisionHandler(.allow) } else { // 其他域名跳Safari UIApplication.shared.open(url, options: [:], completionHandler: nil) decisionHandler(.cancel) } } else { // 处理自定义URL Scheme if UIApplication.shared.canOpenURL(url) { UIApplication.shared.open(url, options: [:], completionHandler: nil) decisionHandler(.cancel) } else { decisionHandler(.allow) } } }
最后检查
别忘了确认你已经给WKWebView设置了navigationDelegate,比如在viewDidLoad里加上这行代码:
override func viewDidLoad() { super.viewDidLoad() webView.navigationDelegate = self loadURLInWebView() }
要是没设置代理,你的decidePolicyFor方法根本不会被触发哦!
内容的提问来源于stack exchange,提问作者Sanjay Mishra




