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

如何处理由webView.uiDelegate打开的页面中的window.close操作?

处理WKWebView中window.open打开页面的window.close操作

针对你已经拦截window.open创建新WKWebView的场景,处理这些新页面里的window.close操作,有两个实用方案,根据你的iOS版本兼容性需求来选:

方案1:注入JS监听+原生消息回调(兼容iOS 11+)

因为网页直接调用window.close无法直接触发原生关闭WebView的逻辑,我们可以通过注入自定义脚本覆盖window.close方法,让它向原生发送一个关闭消息,原生收到后再处理WebView的销毁。

步骤:

  1. 创建WKUserScript覆盖window.close
    写一段JS脚本,把默认的window.close替换成发送消息给原生的逻辑:

    let closeScript = WKUserScript(source: """
        window.close = function() {
            window.webkit.messageHandlers.closeWebView.postMessage(null);
        };
    """, injectionTime: .atDocumentStart, forMainFrameOnly: false)
    
  2. 配置WKWebViewConfiguration并添加消息处理
    在你创建新WKWebView的createWebViewWith方法里,给配置添加这个脚本,同时设置脚本消息处理器:

    func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
        // 添加自定义脚本
        configuration.userContentController.addUserScript(closeScript)
        // 添加消息处理器(记得让当前类遵循WKScriptMessageHandler)
        configuration.userContentController.add(self, name: "closeWebView")
        
        let newWebView = WKWebView(frame: UIScreen.main.bounds, configuration: configuration)
        newWebView.navigationDelegate = self
        // 把新WebView添加到视图或者导航栈(根据你的布局逻辑)
        self.view.addSubview(newWebView)
        // 可以用字典或者数组记录这些WebView,方便后续找到对应实例关闭
        self.openWebViews.append(newWebView)
        return newWebView
    }
    
  3. 实现WKScriptMessageHandler处理关闭消息
    在你的ViewController中实现userContentController(_:didReceive:)方法:

    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if message.name == "closeWebView" {
            // 找到发送消息的WebView实例
            if let webView = message.webView {
                webView.removeFromSuperview()
                // 如果是导航栈里的页面,就用dismiss或者popViewController
                // self.dismiss(animated: true)
                // 同时从记录的数组里移除
                if let index = self.openWebViews.firstIndex(of: webView) {
                    self.openWebViews.remove(at: index)
                }
            }
        }
    }
    

方案2:利用WKWebView的webViewDidClose代理(iOS 14+)

从iOS14开始,WKWebView新增了webViewDidClose(_:)代理方法,当网页调用window.close时,这个回调会被触发——前提是这个WebView是通过window.open创建的(也就是你在createWebViewWith里返回的实例)。

步骤:

  1. 实现WKNavigationDelegate的webViewDidClose方法

    func webViewDidClose(_ webView: WKWebView) {
        // 直接关闭对应的WebView
        webView.removeFromSuperview()
        // 如果是模态弹出的WebViewController,就执行dismiss
        // if let presentingVC = self.presentingViewController {
        //     presentingVC.dismiss(animated: true)
        // }
        // 同样记得从你的WebView记录集合里移除
        if let index = self.openWebViews.firstIndex(of: webView) {
            self.openWebViews.remove(at: index)
        }
    }
    
  2. 确保新WebView的navigationDelegate设置正确
    在你创建新WebView的时候,一定要把它的navigationDelegate设为当前ViewController,这样代理方法才能被触发:

    let newWebView = WKWebView(frame: UIScreen.main.bounds, configuration: configuration)
    newWebView.navigationDelegate = self
    

注意事项:

  • 不管用哪个方案,都要管理好WebView的生命周期,避免内存泄漏——记得在WebView被移除时,移除脚本消息处理器(userContentController.removeScriptMessageHandler(forName: "closeWebView"))。
  • 如果你的新WebView是放在单独的ViewController里展示的,关闭时要对应dismiss或者pop这个ViewController,而不仅仅是移除WebView。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:35:23