You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在多个ViewController中复用WKNavigationDelegate的decidePolicyFor代码

嗨,这个问题我之前也碰到过——重复粘贴相同的代理代码简直是维护噩梦!下面给你分享几种实用的方案,轻松复用decidePolicyFor的逻辑:


方案1:创建独立的WKNavigationDelegate实现类

把代理逻辑抽成一个单独的类,所有ViewController都复用这个类作为导航代理,这是最直接的解耦方式。

步骤1:编写共享代理类

class SharedWebNavigationDelegate: NSObject, WKNavigationDelegate {
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        if let url = navigationAction.request.url, url.scheme == "tel" {
            UIApplication.shared.open(url, options: [:], completionHandler: nil)
            decisionHandler(.cancel)
        } else {
            decisionHandler(.allow)
        }
    }
    
    // 后续需要添加其他WKNavigationDelegate方法的话,直接在这里扩展就行
}

步骤2:在ViewController中使用

class DashboardViewController: UIViewController, WKUIDelegate {
    var webView: WKWebView!
    // 可以做成单例避免重复创建实例,或者每个VC单独持有
    private let navigationDelegate = SharedWebNavigationDelegate()
    
    override func loadView() {
        let webConfiguration = WebViewUtils.getWKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.uiDelegate = self
        webView.navigationDelegate = navigationDelegate // 替换成共享代理
        view = webView
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        webView.load(Constants.DASHBOARD)
    }
}

方案2:使用协议扩展(Protocol Extension)

如果不想额外创建代理对象,协议扩展可以给遵循协议的类提供默认实现,灵活度拉满。

步骤1:定义协议并扩展

protocol WebViewNavigationHandling: WKNavigationDelegate {}

extension WebViewNavigationHandling {
    // 默认实现decidePolicyFor方法
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        if let url = navigationAction.request.url, url.scheme == "tel" {
            UIApplication.shared.open(url, options: [:], completionHandler: nil)
            decisionHandler(.cancel)
        } else {
            decisionHandler(.allow)
        }
    }
}

步骤2:让ViewController遵循协议

class DashboardViewController: UIViewController, WKUIDelegate, WebViewNavigationHandling {
    var webView: WKWebView!
    
    override func loadView() {
        let webConfiguration = WebViewUtils.getWKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.uiDelegate = self
        webView.navigationDelegate = self // 仍然用self,但协议扩展已经提供了默认实现
        view = webView
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        webView.load(Constants.DASHBOARD)
    }
    
    // 不需要再写decidePolicyFor!如果某个VC需要特殊逻辑,直接重写这个方法即可
}

方案3:创建基类ViewController

如果所有带WebView的VC都有大量共同逻辑(比如WebView初始化、基础配置),直接抽一个基类是最省心的。

步骤1:编写基类

class BaseWebViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {
    var webView: WKWebView!
    
    override func loadView() {
        let webConfiguration = WebViewUtils.getWKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.uiDelegate = self
        webView.navigationDelegate = self
        view = webView
    }
    
    // 共享的代理方法实现
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        if let url = navigationAction.request.url, url.scheme == "tel" {
            UIApplication.shared.open(url, options: [:], completionHandler: nil)
            decisionHandler(.cancel)
        } else {
            decisionHandler(.allow)
        }
    }
    
    // 子类重写这个方法加载对应URL
    func loadTargetURL() {}
    
    override func viewDidLoad() {
        super.viewDidLoad()
        loadTargetURL()
    }
}

步骤2:子类继承基类

class DashboardViewController: BaseWebViewController {
    override func loadTargetURL() {
        webView.load(Constants.DASHBOARD)
    }
    
    // 若需要特殊处理代理逻辑,直接重写decidePolicyFor即可
}

方案选择建议

  • 独立代理类:适合代理逻辑和VC业务完全分离的场景,解耦性最好。
  • 协议扩展:灵活度最高,不需要继承,想复用的VC只要遵循协议就行,还能随时重写方法。
  • 基类继承:适合所有WebView VC有大量共同UI/逻辑的情况,一次性搞定所有重复代码。

内容的提问来源于stack exchange,提问作者love2code

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:08:38