60 lines
2.1 KiB
Swift
60 lines
2.1 KiB
Swift
import AppKit
|
|
import SwiftUI
|
|
import WebKit
|
|
|
|
/// Embeds the Feishu record page inside the app. Uses the default persistent
|
|
/// data store, so the Feishu login survives app restarts. Workflow (流程)
|
|
/// fields can't be reached via the API — this is the in-app way to advance them.
|
|
struct FeishuWebView: NSViewRepresentable {
|
|
let url: URL
|
|
|
|
func makeNSView(context: Context) -> WKWebView {
|
|
let configuration = WKWebViewConfiguration()
|
|
configuration.websiteDataStore = .default()
|
|
let webView = WKWebView(frame: .zero, configuration: configuration)
|
|
webView.navigationDelegate = context.coordinator
|
|
webView.allowsBackForwardNavigationGestures = true
|
|
webView.load(URLRequest(url: url))
|
|
return webView
|
|
}
|
|
|
|
func updateNSView(_ webView: WKWebView, context: Context) {
|
|
if webView.url?.absoluteString != url.absoluteString {
|
|
webView.load(URLRequest(url: url))
|
|
}
|
|
}
|
|
|
|
func makeCoordinator() -> Coordinator {
|
|
Coordinator()
|
|
}
|
|
|
|
final class Coordinator: NSObject, WKNavigationDelegate {
|
|
// Only http(s) navigates inside the webview. Custom schemes the page
|
|
// may try (e.g. feishu:// to hand off to the desktop client) are
|
|
// routed to the system instead of failing silently.
|
|
func webView(
|
|
_ webView: WKWebView,
|
|
decidePolicyFor navigationAction: WKNavigationAction
|
|
) async -> WKNavigationActionPolicy {
|
|
guard let url = navigationAction.request.url,
|
|
let scheme = url.scheme else { return .allow }
|
|
if scheme == "http" || scheme == "https" {
|
|
return .allow
|
|
}
|
|
NSWorkspace.shared.open(url)
|
|
return .cancel
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Window content wrapper: WKWebView has no intrinsic size, so a bare hosting
|
|
/// controller collapses the window to ~1px — pin a minimum size here.
|
|
struct FeishuWebWindowContent: View {
|
|
let url: URL
|
|
|
|
var body: some View {
|
|
FeishuWebView(url: url)
|
|
.frame(minWidth: 900, minHeight: 600)
|
|
}
|
|
}
|