macos - 通过 macOS native 应用程序中的 SwiftUI WKWebView 调用时,如何使文件打开对话框正常工作?

标签 macos safari swiftui wkwebview finder

我目前正在运行一个用 SwiftUI 制作的简单的 WkWebView - 我可以从 this StackOverflow post 看到所有建议.它打开一个网站。该网站有一个浏览器按钮。如果我单击 Safari 上的浏览​​器按钮,会打开一个 Finder 窗口。如果我在使用 Xcode 创建的 .app 中执行相同的操作,则不会打开 Finder 窗口。

这是我在沙盒中启用的东西:

XCode App Sandbox settings

我使用的代码是这样的(全部来自 ContentView.swift)

import SwiftUI
import WebKit


public struct WebBrowserView {

    private let webView: WKWebView = WKWebView()

    // ...

    public func load(url: URL) {
        webView.load(URLRequest(url: url))
    }

    public class Coordinator: NSObject, WKNavigationDelegate, WKUIDelegate {

        var parent: WebBrowserView

        init(parent: WebBrowserView) {
            self.parent = parent
        }

        public func webView(_: WKWebView, didFail: WKNavigation!, withError: Error) {
            // ...
        }

        public func webView(_: WKWebView, didFailProvisionalNavigation: WKNavigation!, withError: Error) {
            // ...
        }

        public func webView(_: WKWebView, didFinish: WKNavigation!) {
            // ...
        }

        public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
            // ...
        }

        public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
            decisionHandler(.allow)
        }

        public func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
            if navigationAction.targetFrame == nil {
                webView.load(navigationAction.request)
            }
            return nil
        }
    }

    public func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }
}


#if os(macOS) // macOS Implementation (iOS version omitted for brevity)
extension WebBrowserView: NSViewRepresentable {

    public typealias NSViewType = WKWebView

    public func makeNSView(context: NSViewRepresentableContext<WebBrowserView>) -> WKWebView {

        webView.navigationDelegate = context.coordinator
        webView.uiDelegate = context.coordinator
        return webView
    }

    public func updateNSView(_ nsView: WKWebView, context: NSViewRepresentableContext<WebBrowserView>) {

    }
}
#endif

struct BrowserView: View {

    private let browser = WebBrowserView()

    var body: some View {
        HStack {
            browser
                .onAppear() {
                    self.browser.load(url: URL(string: "http://specificwebsitewithbrowserbutton")!)
                }
        }
        .padding()
    }
}


struct ContentView: View {

    @State private var selection = 1

    var body: some View {
                BrowserView()
                .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
}

那么,我如何给这个 .app 足够的权限,以便当我点击网站上的“上传”按钮时会打开一个 Finder 窗口?

最佳答案

您必须实现以下WKUIDelegate 委托(delegate)方法

   /** @abstract Displays a file upload panel.
     @param webView The web view invoking the delegate method.
     @param parameters Parameters describing the file upload control.
     @param frame Information about the frame whose file upload control initiated this call.
     @param completionHandler The completion handler to call after open panel has been dismissed. Pass the selected URLs if the user chose OK, otherwise nil.
    
     If you do not implement this method, the web view will behave as if the user selected the Cancel button.
     */
    @available(OSX 10.12, *)
    optional func webView(_ webView: WKWebView, runOpenPanelWith 
                  parameters: WKOpenPanelParameters, initiatedByFrame frame: WKFrameInfo, 
                  completionHandler: @escaping ([URL]?) -> Void)

这里是实现的例子

func webView(_ webView: WKWebView, runOpenPanelWith parameters: WKOpenPanelParameters, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping ([URL]?) -> Void) {
    let openPanel = NSOpenPanel()
    openPanel.canChooseFiles = true
    openPanel.begin { (result) in
        if result == NSApplication.ModalResponse.OK {
            if let url = openPanel.url {
                completionHandler([url])
            }
        } else if result == NSApplication.ModalResponse.cancel {
            completionHandler(nil)
        }
    }
}

关于macos - 通过 macOS native 应用程序中的 SwiftUI WKWebView 调用时,如何使文件打开对话框正常工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59804345/

相关文章:

macos - Core Bluetooth 和 IOBluetooth 有什么区别

php - 如何正确加载和 HTML 嵌入受密码保护的文件?

ios - 缩放 SVG 超过未知阈值会导致元素消失

ios - SpriteView 不会在状态更改时暂停场景

SwiftUI AspectRatio 不适用于来自相机的图像

ios - SwiftUI:在特定屏幕上隐藏导航栏

linux - 自从我设置 gitattributes 来处理 crlf 以来,我对中央 git 存档有问题

objective-c - 使用没有 Retina 显示屏的 Retina 图像测试桌面应用程序

macos - 操作 Mac 应用程序中的窗口

css - float div 时 Safari 中的尾随空格?