点击WKWebView内链接触发Completion handler多次调用导致App崩溃如何解决
崩溃原因
你遇到的崩溃是WKNavigationDelegate的强制校验触发的:decidePolicyForNavigationAction的decisionHandler回调必须且仅能调用一次,重复调用就会抛出你遇到的报错并强制崩溃。
你的代码逻辑存在明显漏洞:
- 当点击的是http/https协议的链接、且链接有可加载的目标frame(
navigationAction.targetFrame != nil)时,你先在else分支调用了decisionHandler(.allow),但该分支没有加return终止代码执行,后续代码会继续往下走,再次调用decisionHandler(.cancel),直接触发重复调用的崩溃。 - 同时你在判断targetFrame的逻辑之后还冗余写了一遍外部浏览器打开链接+取消加载的逻辑,和你前面判断targetFrame的分支逻辑完全冲突。
修复后的完整代码
import UIKit import WebKit class Polering: UIViewController, WKNavigationDelegate { // 关联StoryBoard中的webView控件 @IBOutlet weak var webView: WKWebView! override func viewDidLoad() { super.viewDidLoad() // 获取index.html文件路径 guard let htmlPath = Bundle.main.path(forResource: "index", ofType: "html", inDirectory: "www") else { return } // 创建URL用于webView加载 let url = URL(fileURLWithPath: htmlPath) let request = URLRequest(url: url) webView.navigationDelegate = self webView.load(request) } func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { // 校验是否为链接点击 if navigationAction.navigationType == .linkActivated { // 确保URL存在 guard let url = navigationAction.request.url else { decisionHandler(.cancel) return } // 校验URL的scheme组件 let components = URLComponents(url: url, resolvingAgainstBaseURL: false) if components?.scheme == "http" || components?.scheme == "https" { // 新窗口打开的链接跳转外部浏览器 if navigationAction.targetFrame == nil { UIApplication.shared.open(url) decisionHandler(.cancel) } else { // 站内链接直接在当前webView加载 decisionHandler(.allow) } // 处理完http/https链接直接return,避免走后面的默认逻辑 return } else { decisionHandler(.allow) } } else { decisionHandler(.allow) } } }
内容的提问来源于stack exchange,提问作者Peter Jönsson
相关产品推荐
相关产品推荐

