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

SwiftUI中WKWebView配置代理:监听URL并关闭Sheet+跳转Safari

SwiftUI中WKWebView代理实现与Sheet自动关闭方案

1. 嵌套Coordinator实现代理逻辑

在你的WebView结构体内部定义Coordinator类,它将承担WKWebView的代理职责,同时通过绑定值控制Sheet的显示状态:

import SwiftUI
import WebKit

struct WebView: UIViewRepresentable {
    let url: URL
    // 添加绑定值用于控制Sheet的显示/隐藏
    @Binding var isPresented: Bool
    
    // 嵌套Coordinator类处理代理
    class Coordinator: NSObject, WKNavigationDelegate, WKUIDelegate {
        private let parent: WebView
        
        init(_ parent: WebView) {
            self.parent = parent
        }
        
        // 处理target="_blank"链接,跳转至Safari
        func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
            if let url = navigationAction.request.url, UIApplication.shared.canOpenURL(url) {
                UIApplication.shared.open(url)
            }
            return nil
        }
        
        // 监听URL变化,判断是否包含"done"以关闭Sheet
        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            guard let currentUrl = webView.url?.absoluteString else { return }
            if currentUrl.contains("done") {
                parent.isPresented = false
            }
        }
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    func makeUIView(context: Context) -> WKWebView {
        let webView = WKWebView()
        // 设置代理为Coordinator
        webView.navigationDelegate = context.coordinator
        webView.uiDelegate = context.coordinator
        return webView
    }
    
    func updateUIView(_ webView: WKWebView, context: Context) {
        // 避免重复加载相同URL
        if webView.url?.absoluteString != url.absoluteString {
            let request = URLRequest(url: url)
            webView.load(request)
        }
    }
}

2. 修改Sheet中的WebView调用方式

现在需要将控制Sheet显示的绑定值$showModal传递给WebView,这样代理逻辑就能直接修改该值来关闭Sheet:

struct ContentView: View {
    @State private var showModal = false
    
    var body: some View {
        Button {
            showModal.toggle()
        } label: {
            Text("**Check ESPN**")
        }
        .sheet(isPresented: $showModal, onDismiss: {}) {
            // 传递isPresented绑定值
            WebView(url: URL(string: "https://www.espn.com")!, isPresented: $showModal)
        }
    }
}

关键说明

  • 代理逻辑全部封装在Coordinator中,它通过持有WebView实例来访问绑定值isPresented,实现Sheet的自动关闭。
  • 实现WKUIDelegate的createWebViewWith方法,拦截target="_blank"的跳转请求,直接调用系统Safari打开链接。
  • 实现WKNavigationDelegate的didFinish方法,在页面加载完成后检查当前URL是否包含"done",如果是则将isPresented设为false关闭Sheet。
  • updateUIView中增加了URL判断,避免每次状态更新时重复加载相同页面。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 21:09:31