Files
ddys-client/DDYSClient/Views/Auth/WebLoginView.swift
2026-02-26 22:15:35 +08:00

169 lines
5.1 KiB
Swift

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