Skip to content

Instantly share code, notes, and snippets.

@kushwaha03
Created January 5, 2023 13:48
Show Gist options
  • Save kushwaha03/1c2c39dbc542189ac1dc4d777bf44205 to your computer and use it in GitHub Desktop.
Save kushwaha03/1c2c39dbc542189ac1dc4d777bf44205 to your computer and use it in GitHub Desktop.
import UIKit
import WebKit
struct MimeType {
var type:String
var fileExtension:String
}
class WebViewController: UIViewController {
@IBOutlet weak var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
}
}
@available(iOS 14.5, *)
extension WebViewController: WKDownloadDelegate, WKNavigationDelegate {
//WKNavigationDelegate
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
print("Error is::: ",error.localizedDescription)
}
func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
print("Started Commiting")
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
print("Started web load")
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
print("Error is::: ",error.localizedDescription)
}
//WKDownloadDelegate
func webView(_ webView: WKWebView, navigationResponse: WKNavigationResponse, didBecome download: WKDownload) {
download.delegate = self
}
func webView(_ webView: WKWebView, navigationAction: WKNavigationAction, didBecome download: WKDownload) {
download.delegate = self
}
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
if let mimeType = navigationResponse.response.mimeType {
if isMimeTypeConfigured(mimeType) {
if let url = navigationResponse.response.url {
if #available(iOS 14.5, *) {
decisionHandler(.download)
} else {
var fileName = getDefaultFileName(forMimeType: mimeType)
if let name = getFileNameFromResponse(navigationResponse.response) {
fileName = name
}
downloadData(fromURL: url, fileName: fileName) { success, destinationURL in
if success, let destinationURL = destinationURL {
self.openDownloadFile(destinationURL) }
}
decisionHandler(.cancel)
}
return
}
}
}
decisionHandler(.allow)
}
private func isMimeTypeConfigured(_ mimeType:String) -> Bool {
for record in self.mimeTypes {
if mimeType.contains(record.type) {
return true
}
}
return false
}
private func getDefaultFileName(forMimeType mimeType:String) -> String {
for record in self.mimeTypes {
if mimeType.contains(record.type) {
return "default." + record.fileExtension
}
}
return "default"
}
private func getFileNameFromResponse(_ response:URLResponse) -> String? {
if let httpResponse = response as? HTTPURLResponse {
let headers = httpResponse.allHeaderFields
if let disposition = headers["Content-Disposition"] as? String {
let components = disposition.components(separatedBy: " ")
if components.count > 1 {
let innerComponents = components[1].components(separatedBy: "=")
if innerComponents.count > 1 {
if innerComponents[0].contains("filename") {
return innerComponents[1]
}
}
}
}
}
return nil
}
private func downloadData(fromURL url: URL,
fileName: String,
completion: @escaping (Bool, URL?) -> Void) {
webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in
let session = URLSession.shared
session.configuration.httpCookieStorage?.setCookies(cookies, for: url, mainDocumentURL: nil)
let task = session.downloadTask(with: url) { localURL, _, error in
if let localURL = localURL {
let destinationURL = self.moveDownloadedFile(url: localURL, fileName: fileName)
completion(true, destinationURL)
} else {
completion(false, nil)
}
}
task.resume()
}
}
private func moveDownloadedFile(url: URL, fileName: String) -> URL {
let tempDir = NSTemporaryDirectory()
let destinationPath = tempDir + fileName
let destinationURL = URL(fileURLWithPath: destinationPath)
try? FileManager.default.removeItem(at: destinationURL)
try? FileManager.default.moveItem(at: url, to: destinationURL)
return destinationURL
}
private func openDownloadFile(_ fileUrl: URL) {
DispatchQueue.main.async {
let controller = UIActivityViewController(activityItems: [fileUrl], applicationActivities: nil)
controller.popoverPresentationController?.sourceView = self.view
controller.popoverPresentationController?.sourceRect = self.view.frame
controller.popoverPresentationController?.barButtonItem = self.navigationItem.rightBarButtonItem
self.present(controller, animated: true, completion: nil)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment