import SwiftUI #if canImport(WebKit) import WebKit struct WebLoginView: View { @Environment(\.dismiss) private var dismiss @State private var isLoading = true var body: some View { NavigationStack { ZStack { WebLoginRepresentable( url: URL(string: "https://ddys.io")!, isLoading: $isLoading, onCookiesExtracted: { cookies in CookieManager.shared.cookieString = cookies dismiss() } ) if isLoading { ProgressView("加载中...") } } .navigationTitle("登录 DDYS") #if os(iOS) .navigationBarTitleDisplayMode(.inline) #endif .toolbar { ToolbarItem(placement: .cancellationAction) { Button("取消") { dismiss() } } ToolbarItem(placement: .confirmationAction) { Button("提取 Cookie") { // 通知 WebView 提取 cookies NotificationCenter.default.post(name: .extractCookies, object: nil) } } } } } } extension Notification.Name { static let extractCookies = Notification.Name("extractCookies") } #if os(iOS) struct WebLoginRepresentable: UIViewRepresentable { let url: URL @Binding var isLoading: Bool let onCookiesExtracted: (String) -> Void func makeUIView(context: Context) -> WKWebView { let config = WKWebViewConfiguration() let webView = WKWebView(frame: .zero, configuration: config) webView.navigationDelegate = context.coordinator webView.load(URLRequest(url: url)) NotificationCenter.default.addObserver( context.coordinator, selector: #selector(Coordinator.extractCookies), name: .extractCookies, object: nil ) return webView } func updateUIView(_ uiView: WKWebView, context: Context) {} func makeCoordinator() -> Coordinator { Coordinator(parent: self) } class Coordinator: NSObject, WKNavigationDelegate { let parent: WebLoginRepresentable weak var webView: WKWebView? init(parent: WebLoginRepresentable) { self.parent = parent } func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { self.webView = webView parent.isLoading = true } func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { parent.isLoading = false } @objc func extractCookies() { guard let webView else { return } webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in let ddysCookies = cookies .filter { $0.domain.contains("ddys") } .map { "\($0.name)=\($0.value)" } .joined(separator: "; ") DispatchQueue.main.async { self.parent.onCookiesExtracted(ddysCookies) } } } } } #else struct WebLoginRepresentable: NSViewRepresentable { let url: URL @Binding var isLoading: Bool let onCookiesExtracted: (String) -> Void func makeNSView(context: Context) -> WKWebView { let config = WKWebViewConfiguration() let webView = WKWebView(frame: .zero, configuration: config) webView.navigationDelegate = context.coordinator webView.load(URLRequest(url: url)) NotificationCenter.default.addObserver( context.coordinator, selector: #selector(Coordinator.extractCookies), name: .extractCookies, object: nil ) return webView } func updateNSView(_ nsView: WKWebView, context: Context) {} func makeCoordinator() -> Coordinator { Coordinator(parent: self) } class Coordinator: NSObject, WKNavigationDelegate { let parent: WebLoginRepresentable weak var webView: WKWebView? init(parent: WebLoginRepresentable) { self.parent = parent } func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { self.webView = webView parent.isLoading = true } func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { parent.isLoading = false } @objc func extractCookies() { guard let webView else { return } webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in let ddysCookies = cookies .filter { $0.domain.contains("ddys") } .map { "\($0.name)=\($0.value)" } .joined(separator: "; ") DispatchQueue.main.async { self.parent.onCookiesExtracted(ddysCookies) } } } } } #endif #endif