简体   繁体   English

如何在 macOS 上从 WKWebview 内部下载文件

[英]How to download files from inside WKWebview on macOS

so I'll keep it short.所以我会保持简短。 AS the title says I have an a web view embedded in my SwiftUI application for macOS and there's a link on the website which downloads a.doc file.正如标题所说,我的 SwiftUI 应用程序中嵌入了一个 web 视图,并且网站上有一个下载 a.doc 文件的链接。 However WKWebView doesn't really let you know download stuff from the internet like that.然而,WKWebView 并没有真正让你知道从互联网上下载东西。 I looked around SO and there are a few ways to solve it but none of them pertain to SwiftUI.我环顾四周,有几种方法可以解决它,但没有一个与 SwiftUI 相关。 Does anyone know how can I simply download a normal text file from a website onto the Mac using WKWebView in SwiftUI?有谁知道如何使用 SwiftUI 中的 WKWebView 将普通文本文件从网站下载到 Mac 上?

Here's my WebView code:这是我的 WebView 代码:

  import SwiftUI
  import WebKit
  import Combine

  class WebViewData: ObservableObject {
  @Published var loading: Bool = false
  @Published var url: URL?;
var popupWebView: WKWebView?
  init (url: URL) {
  self.url = url
 }
 }

 @available(OSX 11.0, *)
 struct WebView: NSViewRepresentable {
 @ObservedObject var data: WebViewData

  func makeNSView(context: Context) -> WKWebView {
   return context.coordinator.webView
    }

 func updateNSView(_ nsView: WKWebView, context: Context) {

guard context.coordinator.loadedUrl != data.url else { return }
context.coordinator.loadedUrl = data.url

if let url = data.url {
  DispatchQueue.main.async {
    let request = URLRequest(url: url)
    nsView.load(request)
  }
}

context.coordinator.data.url = data.url
  }

      func makeCoordinator() -> WebViewCoordinator {
    return WebViewCoordinator(data: data)
   }
  }

 @available(OSX 11.0, *)
class WebViewCoordinator: NSObject, WKNavigationDelegate {
  @ObservedObject var data: WebViewData

  var webView: WKWebView = WKWebView()
  var loadedUrl: URL? = nil

  init(data: WebViewData) {
     self.data = data

  super.init()

webView.navigationDelegate = self
 }

  func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
DispatchQueue.main.async {
  self.data.loading = false
   }
   }

   func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation:     WKNavigation!) {
DispatchQueue.main.async { self.data.loading = true }
   }

  func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError.   error: Error) {
   showError(title: "Navigation Error", message: error.localizedDescription)
    DispatchQueue.main.async { self.data.loading = false }
  }

  func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
    showError(title: "Loading Error", message: error.localizedDescription)
DispatchQueue.main.async { self.data.loading = false }
  }


  func showError(title: String, message: String) {
#if os(macOS)
let alert: NSAlert = NSAlert()

alert.messageText = title
alert.informativeText = message
alert.alertStyle = .warning

alert.runModal()
#else
print("\(title): \(message)")
#endif
  }
 }

Here's my Content View这是我的内容视图

  import SwiftUI

 @available(OSX 11.0, *)

 struct ContentView: View {


 private var url: URL? = URL(string: "https://mywebsite.com")

   init() {
print("Hello World")
   }

   var body: some View {
  
  
WebView(data: WebViewData(url: self.url!))
      .frame(minWidth: 1400, idealWidth: 1500, minHeight: 850, idealHeight: 850)
  
  }



 }

Also here's how my website downloads the files using JS in case anyone's interested:另外,如果有人感兴趣,我的网站如何使用 JS 下载文件:

    function exportworddocument(){
 
   var sourceHTML = document.getElementById("notes").innerHTML;
     
   var source = 'data:application/vnd.ms-word;charset=utf-8,' +    encodeURIComponent(sourceHTML);
   var fileDownload = document.createElement("a");
   document.body.appendChild(fileDownload);
   fileDownload.href = source;
 
   var lines = $('#notes').val().split('.');//gives all lines
    const firstLine=lines[0];
  console.log(firstLine)
   fileDownload.download = firstLine + ".doc";
   fileDownload.click();
   document.body.removeChild(fileDownload);
}

We have to implement some of the decision policy callbacks as WKNavigationDelegate , like我们必须将一些决策策略回调实现为WKNavigationDelegate ,例如

    // early decision per URL
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        if navigationAction.request.url?.pathExtension == "doc" {
            decisionHandler(.download)
        } else {
            decisionHandler(.allow)
        }
    }

    // when known response
    func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
        if navigationResponse.response.mimeType == "your type" {
            decisionHandler(.download)
        } else {
            decisionHandler(.allow)
        }
    }

Have your WebViewCoordinator implement WKDownloadDelegate so it can handle a WKDownload .让您的WebViewCoordinator实现WKDownloadDelegate以便它可以处理WKDownload Implement webView(_:decidePolicyFor:decisionHandler:) to call decisionHandler(.download) for the files you want to download, and then implement download(_:decideDestinationUsing:suggestedFilename:completionHandler:) to choose the download destination for a given request.实现webView(_:decidePolicyFor:decisionHandler:)为您要下载的文件调用decisionHandler(.download) ,然后实现download(_:decideDestinationUsing:suggestedFilename:completionHandler:)为给定请求选择下载目的地。

A more expansive answer to a similar question is available at How to download files in wkwebview , and there's a good blog post on the topic at: http://www.gfrigerio.com/download-files-in-a-wkwebview/ How to download files in wkwebview提供了对类似问题的更广泛的答案,并且有一篇关于该主题的很好的博客文章: http://www.gfrigerio.com/download-files-in-a-wkwebview/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM