Swift WebView调用goBack/goForward后随机启动外部浏览器求助
解决WebView调用goBack/goForward后随机跳转到外部浏览器的问题
这个问题我之前踩过坑!大概率是WebView在导航状态不稳定的时候(比如快速点击按钮触发多次请求、网络断连时加载失败),触发了系统默认的外部跳转 fallback,或者是你的导航代理没有正确拦截住前进后退后的页面跳转请求。给你几个亲测有效的解决办法:
1. 严格控制导航状态,防止重复触发
快速点击按钮会导致WebView同时处理多个前进/后退请求,很容易打乱导航状态,进而触发外部跳转。我们可以通过一个标记变量来控制导航操作的唯一性,同时实时同步WebView的导航状态到按钮的可用状态:
// 新增变量标记是否正在处理导航 private var isNavigating = false @IBAction func didClickNextBtn(_ sender: Any) { // 只有当可以前进且未在导航中时才执行操作 guard webView.canGoForward, !isNavigating else { return } isNavigating = true webView.goForward() } @IBAction func didClickBackBtn(_ sender: Any) { guard webView.canGoBack, !isNavigating else { return } isNavigating = true webView.goBack() } // 实现WKNavigationDelegate的方法来更新导航状态 extension YourViewController: WKNavigationDelegate { func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { isNavigating = true } func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { isNavigating = false // 实时更新按钮可用状态 nextBtn.isEnabled = webView.canGoForward backBtn.isEnabled = webView.canGoBack } func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { isNavigating = false // 加载失败时也更新按钮状态,避免按钮卡死 nextBtn.isEnabled = webView.canGoForward backBtn.isEnabled = webView.canGoBack // 这里可以加个错误提示,比如Toast告诉用户加载失败 } }
⚠️ 别忘了给你的WebView设置代理:webView.navigationDelegate = self
2. 拦截所有导航请求,强制在当前WebView内打开
有时候前进后退后的页面可能会触发新窗口跳转(比如某些网页的跳转逻辑),这时候系统会默认调用外部浏览器。我们可以通过导航代理拦截所有请求,强制在当前WebView加载:
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { // 如果是主框架的导航请求,直接允许在当前WebView加载 if navigationAction.targetFrame?.isMainFrame == true { decisionHandler(.allow) } else { // 如果是新窗口请求,拦截并在当前WebView加载该请求 webView.load(navigationAction.request) decisionHandler(.cancel) } }
3. 网络异常时提前拦截操作
当网络断开时,WebView尝试前进/后退会加载失败,进而可能触发外部跳转的 fallback。我们可以监听网络状态,在无网络时直接禁用前进后退按钮:
import Network private var networkMonitor: NWPathMonitor! override func viewDidLoad() { super.viewDidLoad() setupNetworkMonitor() } private func setupNetworkMonitor() { networkMonitor = NWPathMonitor() networkMonitor.pathUpdateHandler = { [weak self] path in DispatchQueue.main.async { let isNetworkAvailable = path.status == .satisfied // 只有网络可用且WebView可以前进/后退时,才启用按钮 self?.nextBtn.isEnabled = isNetworkAvailable && (self?.webView.canGoForward ?? false) self?.backBtn.isEnabled = isNetworkAvailable && (self?.webView.canGoBack ?? false) } } // 在后台队列监听网络状态 let monitorQueue = DispatchQueue(label: "NetworkStatusMonitor") networkMonitor.start(queue: monitorQueue) } // 记得在页面销毁时停止监听,避免内存泄漏 deinit { networkMonitor.cancel() }
把这几个方案结合起来,基本就能解决快速点击或网络异常时的外部跳转问题了!
内容的提问来源于stack exchange,提问作者Natan Tashimov
相关产品推荐
相关产品推荐

