├── WKWebViewDownloadHelper
├── Assets.xcassets
│ ├── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── AppDelegate.swift
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── Info.plist
├── SceneDelegate.swift
├── ViewController.swift
└── WKWebViewDownloadHelper.swift
├── WKWebViewDownloadHelper.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcuserdata
│ │ └── gualtierofrigerio.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcuserdata
│ └── gualtierofrigerio.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
└── project.pbxproj
└── README.md
/WKWebViewDownloadHelper/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/WKWebViewDownloadHelper.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/WKWebViewDownloadHelper.xcodeproj/project.xcworkspace/xcuserdata/gualtierofrigerio.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gualtierofrigerio/WKWebViewDownloadHelper/HEAD/WKWebViewDownloadHelper.xcodeproj/project.xcworkspace/xcuserdata/gualtierofrigerio.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/WKWebViewDownloadHelper.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WKWebViewDownloadHelper
2 |
3 | Sample project to show how to download a file in a WKWebView.
4 |
5 | See this blog post for details [Download files in a WKWebView](https://www.gfrigerio.com/download-files-in-a-wkwebview/)
6 |
7 | If you need to add this code to your project a Swift Package to import via SPM is available [here](https://github.com/gualtierofrigerio/WKDownloadHelper)
8 |
9 |
10 |
--------------------------------------------------------------------------------
/WKWebViewDownloadHelper.xcodeproj/xcuserdata/gualtierofrigerio.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | WKWebViewDownloadHelper.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/WKWebViewDownloadHelper/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // WKWebViewDownloadHelper
4 | //
5 | // Created by Gualtiero Frigerio on 03/07/2020.
6 | // Copyright © 2020 Gualtiero Frigerio. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 |
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
17 | // Override point for customization after application launch.
18 | return true
19 | }
20 |
21 | // MARK: UISceneSession Lifecycle
22 |
23 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
24 | // Called when a new scene session is being created.
25 | // Use this method to select a configuration to create the new scene with.
26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
27 | }
28 |
29 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
30 | // Called when the user discards a scene session.
31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
33 | }
34 |
35 |
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/WKWebViewDownloadHelper/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/WKWebViewDownloadHelper/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/WKWebViewDownloadHelper/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 | UISceneStoryboardFile
37 | Main
38 |
39 |
40 |
41 |
42 | UILaunchStoryboardName
43 | LaunchScreen
44 | UIMainStoryboardFile
45 | Main
46 | UIRequiredDeviceCapabilities
47 |
48 | armv7
49 |
50 | UISupportedInterfaceOrientations
51 |
52 | UIInterfaceOrientationPortrait
53 | UIInterfaceOrientationLandscapeLeft
54 | UIInterfaceOrientationLandscapeRight
55 |
56 | UISupportedInterfaceOrientations~ipad
57 |
58 | UIInterfaceOrientationPortrait
59 | UIInterfaceOrientationPortraitUpsideDown
60 | UIInterfaceOrientationLandscapeLeft
61 | UIInterfaceOrientationLandscapeRight
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/WKWebViewDownloadHelper/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // WKWebViewDownloadHelper
4 | //
5 | // Created by Gualtiero Frigerio on 03/07/2020.
6 | // Copyright © 2020 Gualtiero Frigerio. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
12 |
13 | var window: UIWindow?
14 |
15 |
16 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
17 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
18 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
19 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
20 | guard let _ = (scene as? UIWindowScene) else { return }
21 | }
22 |
23 | func sceneDidDisconnect(_ scene: UIScene) {
24 | // Called as the scene is being released by the system.
25 | // This occurs shortly after the scene enters the background, or when its session is discarded.
26 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
27 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
28 | }
29 |
30 | func sceneDidBecomeActive(_ scene: UIScene) {
31 | // Called when the scene has moved from an inactive state to an active state.
32 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
33 | }
34 |
35 | func sceneWillResignActive(_ scene: UIScene) {
36 | // Called when the scene will move from an active state to an inactive state.
37 | // This may occur due to temporary interruptions (ex. an incoming phone call).
38 | }
39 |
40 | func sceneWillEnterForeground(_ scene: UIScene) {
41 | // Called as the scene transitions from the background to the foreground.
42 | // Use this method to undo the changes made on entering the background.
43 | }
44 |
45 | func sceneDidEnterBackground(_ scene: UIScene) {
46 | // Called as the scene transitions from the foreground to the background.
47 | // Use this method to save data, release shared resources, and store enough scene-specific state information
48 | // to restore the scene back to its current state.
49 | }
50 |
51 |
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/WKWebViewDownloadHelper/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // WkWebViewTest
4 | //
5 | // Created by Gualtiero Frigerio on 03/07/2020.
6 | // Copyright © 2020 Gualtiero Frigerio. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import WebKit
11 | import WKDownloadHelper
12 |
13 | class ViewController: UIViewController {
14 | var webView:WKWebView!
15 | //var helper:WKWebviewDownloadHelper!
16 | var downloadHelper: WKDownloadHelper!
17 |
18 | override func viewDidLoad() {
19 | super.viewDidLoad()
20 |
21 | let webView = WKWebView(frame: self.view.frame)
22 | self.view.addSubview(webView)
23 | webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
24 | let mimeTypes = [MimeType(type: "ms-excel", fileExtension: "xls"),
25 | MimeType(type: "pdf", fileExtension: "pdf")]
26 | //helper = WKWebviewDownloadHelper(webView: webView, mimeTypes:mimeTypes, delegate: self)
27 | downloadHelper = WKDownloadHelper(webView: webView, supportedMimeTypes: mimeTypes, delegate: self)
28 | let request = URLRequest(url: URL(string: "https://www.google.it")!)
29 | webView.load(request)
30 | self.webView = webView
31 | self.navigationItem.title = "My Page"
32 | self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .close, target: nil, action: nil)
33 | }
34 | }
35 |
36 | // OLD implementation
37 | //extension ViewController: WKWebViewDownloadHelperDelegate {
38 | // func fileDownloadedAtURL(url: URL) {
39 | // DispatchQueue.main.async {
40 | // let activityVC = UIActivityViewController(activityItems: [url], applicationActivities: nil)
41 | // activityVC.popoverPresentationController?.sourceView = self.view
42 | // activityVC.popoverPresentationController?.sourceRect = self.view.frame
43 | // activityVC.popoverPresentationController?.barButtonItem = self.navigationItem.rightBarButtonItem
44 | // self.present(activityVC, animated: true, completion: nil)
45 | // }
46 | // }
47 | //}
48 |
49 | extension ViewController: WKDownloadHelperDelegate {
50 | func canNavigate(toUrl: URL) -> Bool {
51 | true
52 | }
53 |
54 | func didFailDownloadingFile(error: Error) {
55 | print("error while downloading file \(error)")
56 | }
57 |
58 | func didDownloadFile(atUrl: URL) {
59 | print("did download file!")
60 | DispatchQueue.main.async {
61 | let activityVC = UIActivityViewController(activityItems: [atUrl], applicationActivities: nil)
62 | activityVC.popoverPresentationController?.sourceView = self.view
63 | activityVC.popoverPresentationController?.sourceRect = self.view.frame
64 | activityVC.popoverPresentationController?.barButtonItem = self.navigationItem.rightBarButtonItem
65 | self.present(activityVC, animated: true, completion: nil)
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/WKWebViewDownloadHelper/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/WKWebViewDownloadHelper/WKWebViewDownloadHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WKWebViewDownloadHelper.swift
3 | // WkWebViewTest
4 | //
5 | // Created by Gualtiero Frigerio on 03/07/2020.
6 | // Copyright © 2020 Gualtiero Frigerio. All rights reserved.
7 | //
8 |
9 | // OLD implementation
10 | // The helper is now distributed as SPM
11 |
12 | import Foundation
13 | import WebKit
14 |
15 | struct MimeType {
16 | var type:String
17 | var fileExtension:String
18 | }
19 |
20 | protocol WKWebViewDownloadHelperDelegate {
21 | func fileDownloadedAtURL(url:URL)
22 | }
23 |
24 | class WKWebviewDownloadHelper:NSObject {
25 |
26 | var webView:WKWebView
27 | var mimeTypes:[MimeType]
28 | var delegate:WKWebViewDownloadHelperDelegate
29 |
30 | init(webView:WKWebView, mimeTypes:[MimeType], delegate:WKWebViewDownloadHelperDelegate) {
31 | self.webView = webView
32 | self.mimeTypes = mimeTypes
33 | self.delegate = delegate
34 | super.init()
35 | webView.navigationDelegate = self
36 | }
37 |
38 | private var fileDestinationURL: URL?
39 |
40 | private func downloadData(fromURL url:URL,
41 | fileName:String,
42 | completion:@escaping (Bool, URL?) -> Void) {
43 | webView.configuration.websiteDataStore.httpCookieStore.getAllCookies() { cookies in
44 | let session = URLSession.shared
45 | session.configuration.httpCookieStorage?.setCookies(cookies, for: url, mainDocumentURL: nil)
46 | let task = session.downloadTask(with: url) { localURL, urlResponse, error in
47 | if let localURL = localURL {
48 | let destinationURL = self.moveDownloadedFile(url: localURL, fileName: fileName)
49 | completion(true, destinationURL)
50 | }
51 | else {
52 | completion(false, nil)
53 | }
54 | }
55 |
56 | task.resume()
57 | }
58 | }
59 |
60 | private func getDefaultFileName(forMimeType mimeType:String) -> String {
61 | for record in self.mimeTypes {
62 | if mimeType.contains(record.type) {
63 | return "default." + record.fileExtension
64 | }
65 | }
66 | return "default"
67 | }
68 |
69 | private func getFileNameFromResponse(_ response:URLResponse) -> String? {
70 | if let httpResponse = response as? HTTPURLResponse {
71 | let headers = httpResponse.allHeaderFields
72 | if let disposition = headers["Content-Disposition"] as? String {
73 | let components = disposition.components(separatedBy: " ")
74 | if components.count > 1 {
75 | let innerComponents = components[1].components(separatedBy: "=")
76 | if innerComponents.count > 1 {
77 | if innerComponents[0].contains("filename") {
78 | return innerComponents[1]
79 | }
80 | }
81 | }
82 | }
83 | }
84 | return nil
85 | }
86 |
87 | private func isMimeTypeConfigured(_ mimeType:String) -> Bool {
88 | for record in self.mimeTypes {
89 | if mimeType.contains(record.type) {
90 | return true
91 | }
92 | }
93 | return false
94 | }
95 |
96 | private func moveDownloadedFile(url:URL, fileName:String) -> URL {
97 | let tempDir = NSTemporaryDirectory()
98 | let destinationPath = tempDir + fileName
99 | let destinationURL = URL(fileURLWithPath: destinationPath)
100 | try? FileManager.default.removeItem(at: destinationURL)
101 | try? FileManager.default.moveItem(at: url, to: destinationURL)
102 | return destinationURL
103 | }
104 | }
105 |
106 | extension WKWebviewDownloadHelper: WKNavigationDelegate {
107 | func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
108 | decisionHandler(.allow)
109 | }
110 |
111 | func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
112 | if let mimeType = navigationResponse.response.mimeType {
113 | if isMimeTypeConfigured(mimeType) {
114 | if let url = navigationResponse.response.url {
115 | if #available(iOS 14.5, *) {
116 | decisionHandler(.download)
117 | } else {
118 | var fileName = getDefaultFileName(forMimeType: mimeType)
119 | if let name = getFileNameFromResponse(navigationResponse.response) {
120 | fileName = name
121 | }
122 | downloadData(fromURL: url, fileName: fileName) { success, destinationURL in
123 | if success, let destinationURL = destinationURL {
124 | self.delegate.fileDownloadedAtURL(url: destinationURL)
125 | }
126 | }
127 | decisionHandler(.cancel)
128 | }
129 | return
130 | }
131 | }
132 | }
133 | decisionHandler(.allow)
134 | }
135 |
136 | @available(iOS 14.5, *)
137 | func webView(_ webView: WKWebView, navigationResponse: WKNavigationResponse, didBecome download: WKDownload) {
138 | print(" navigationresponse didbecome download ")
139 | download.delegate = self
140 | }
141 | }
142 |
143 | @available(iOS 14.5, *)
144 | extension WKWebviewDownloadHelper: WKDownloadDelegate {
145 | func download(_ download: WKDownload, decideDestinationUsing response: URLResponse, suggestedFilename: String, completionHandler: @escaping (URL?) -> Void) {
146 | let temporaryDir = NSTemporaryDirectory()
147 | let fileName = temporaryDir + "/" + suggestedFilename
148 | let url = URL(fileURLWithPath: fileName)
149 | fileDestinationURL = url
150 | completionHandler(url)
151 | }
152 |
153 | func download(_ download: WKDownload, didFailWithError error: Error, resumeData: Data?) {
154 | print("download failed \(error)")
155 | }
156 |
157 | func downloadDidFinish(_ download: WKDownload) {
158 | print("download finish")
159 | if let url = fileDestinationURL {
160 | self.delegate.fileDownloadedAtURL(url: url)
161 | }
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/WKWebViewDownloadHelper.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 52;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 254405F224AFB44C00C32DC8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 254405F124AFB44C00C32DC8 /* AppDelegate.swift */; };
11 | 254405F424AFB44C00C32DC8 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 254405F324AFB44C00C32DC8 /* SceneDelegate.swift */; };
12 | 254405F624AFB44C00C32DC8 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 254405F524AFB44C00C32DC8 /* ViewController.swift */; };
13 | 254405F924AFB44C00C32DC8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 254405F724AFB44C00C32DC8 /* Main.storyboard */; };
14 | 254405FB24AFB44E00C32DC8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 254405FA24AFB44E00C32DC8 /* Assets.xcassets */; };
15 | 254405FE24AFB44E00C32DC8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 254405FC24AFB44E00C32DC8 /* LaunchScreen.storyboard */; };
16 | 258F07082674DAF6003DC7EF /* WKDownloadHelper in Frameworks */ = {isa = PBXBuildFile; productRef = 258F07072674DAF6003DC7EF /* WKDownloadHelper */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXFileReference section */
20 | 254405EE24AFB44C00C32DC8 /* WKWebViewDownloadHelper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WKWebViewDownloadHelper.app; sourceTree = BUILT_PRODUCTS_DIR; };
21 | 254405F124AFB44C00C32DC8 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
22 | 254405F324AFB44C00C32DC8 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
23 | 254405F524AFB44C00C32DC8 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
24 | 254405F824AFB44C00C32DC8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
25 | 254405FA24AFB44E00C32DC8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
26 | 254405FD24AFB44E00C32DC8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
27 | 254405FF24AFB44E00C32DC8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
28 | 2544060524AFB47500C32DC8 /* WKWebViewDownloadHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKWebViewDownloadHelper.swift; sourceTree = ""; };
29 | /* End PBXFileReference section */
30 |
31 | /* Begin PBXFrameworksBuildPhase section */
32 | 254405EB24AFB44C00C32DC8 /* Frameworks */ = {
33 | isa = PBXFrameworksBuildPhase;
34 | buildActionMask = 2147483647;
35 | files = (
36 | 258F07082674DAF6003DC7EF /* WKDownloadHelper in Frameworks */,
37 | );
38 | runOnlyForDeploymentPostprocessing = 0;
39 | };
40 | /* End PBXFrameworksBuildPhase section */
41 |
42 | /* Begin PBXGroup section */
43 | 254405E524AFB44C00C32DC8 = {
44 | isa = PBXGroup;
45 | children = (
46 | 254405F024AFB44C00C32DC8 /* WKWebViewDownloadHelper */,
47 | 254405EF24AFB44C00C32DC8 /* Products */,
48 | );
49 | sourceTree = "";
50 | };
51 | 254405EF24AFB44C00C32DC8 /* Products */ = {
52 | isa = PBXGroup;
53 | children = (
54 | 254405EE24AFB44C00C32DC8 /* WKWebViewDownloadHelper.app */,
55 | );
56 | name = Products;
57 | sourceTree = "";
58 | };
59 | 254405F024AFB44C00C32DC8 /* WKWebViewDownloadHelper */ = {
60 | isa = PBXGroup;
61 | children = (
62 | 254405F124AFB44C00C32DC8 /* AppDelegate.swift */,
63 | 254405F324AFB44C00C32DC8 /* SceneDelegate.swift */,
64 | 254405F524AFB44C00C32DC8 /* ViewController.swift */,
65 | 2544060524AFB47500C32DC8 /* WKWebViewDownloadHelper.swift */,
66 | 254405F724AFB44C00C32DC8 /* Main.storyboard */,
67 | 254405FA24AFB44E00C32DC8 /* Assets.xcassets */,
68 | 254405FC24AFB44E00C32DC8 /* LaunchScreen.storyboard */,
69 | 254405FF24AFB44E00C32DC8 /* Info.plist */,
70 | );
71 | path = WKWebViewDownloadHelper;
72 | sourceTree = "";
73 | };
74 | /* End PBXGroup section */
75 |
76 | /* Begin PBXNativeTarget section */
77 | 254405ED24AFB44C00C32DC8 /* WKWebViewDownloadHelper */ = {
78 | isa = PBXNativeTarget;
79 | buildConfigurationList = 2544060224AFB44E00C32DC8 /* Build configuration list for PBXNativeTarget "WKWebViewDownloadHelper" */;
80 | buildPhases = (
81 | 254405EA24AFB44C00C32DC8 /* Sources */,
82 | 254405EB24AFB44C00C32DC8 /* Frameworks */,
83 | 254405EC24AFB44C00C32DC8 /* Resources */,
84 | );
85 | buildRules = (
86 | );
87 | dependencies = (
88 | );
89 | name = WKWebViewDownloadHelper;
90 | packageProductDependencies = (
91 | 258F07072674DAF6003DC7EF /* WKDownloadHelper */,
92 | );
93 | productName = WKWebViewDownloadHelper;
94 | productReference = 254405EE24AFB44C00C32DC8 /* WKWebViewDownloadHelper.app */;
95 | productType = "com.apple.product-type.application";
96 | };
97 | /* End PBXNativeTarget section */
98 |
99 | /* Begin PBXProject section */
100 | 254405E624AFB44C00C32DC8 /* Project object */ = {
101 | isa = PBXProject;
102 | attributes = {
103 | LastSwiftUpdateCheck = 1150;
104 | LastUpgradeCheck = 1150;
105 | ORGANIZATIONNAME = "Gualtiero Frigerio";
106 | TargetAttributes = {
107 | 254405ED24AFB44C00C32DC8 = {
108 | CreatedOnToolsVersion = 11.5;
109 | };
110 | };
111 | };
112 | buildConfigurationList = 254405E924AFB44C00C32DC8 /* Build configuration list for PBXProject "WKWebViewDownloadHelper" */;
113 | compatibilityVersion = "Xcode 9.3";
114 | developmentRegion = en;
115 | hasScannedForEncodings = 0;
116 | knownRegions = (
117 | en,
118 | Base,
119 | );
120 | mainGroup = 254405E524AFB44C00C32DC8;
121 | packageReferences = (
122 | 258F07062674DAF6003DC7EF /* XCRemoteSwiftPackageReference "WKDownloadHelper" */,
123 | );
124 | productRefGroup = 254405EF24AFB44C00C32DC8 /* Products */;
125 | projectDirPath = "";
126 | projectRoot = "";
127 | targets = (
128 | 254405ED24AFB44C00C32DC8 /* WKWebViewDownloadHelper */,
129 | );
130 | };
131 | /* End PBXProject section */
132 |
133 | /* Begin PBXResourcesBuildPhase section */
134 | 254405EC24AFB44C00C32DC8 /* Resources */ = {
135 | isa = PBXResourcesBuildPhase;
136 | buildActionMask = 2147483647;
137 | files = (
138 | 254405FE24AFB44E00C32DC8 /* LaunchScreen.storyboard in Resources */,
139 | 254405FB24AFB44E00C32DC8 /* Assets.xcassets in Resources */,
140 | 254405F924AFB44C00C32DC8 /* Main.storyboard in Resources */,
141 | );
142 | runOnlyForDeploymentPostprocessing = 0;
143 | };
144 | /* End PBXResourcesBuildPhase section */
145 |
146 | /* Begin PBXSourcesBuildPhase section */
147 | 254405EA24AFB44C00C32DC8 /* Sources */ = {
148 | isa = PBXSourcesBuildPhase;
149 | buildActionMask = 2147483647;
150 | files = (
151 | 254405F624AFB44C00C32DC8 /* ViewController.swift in Sources */,
152 | 254405F224AFB44C00C32DC8 /* AppDelegate.swift in Sources */,
153 | 254405F424AFB44C00C32DC8 /* SceneDelegate.swift in Sources */,
154 | );
155 | runOnlyForDeploymentPostprocessing = 0;
156 | };
157 | /* End PBXSourcesBuildPhase section */
158 |
159 | /* Begin PBXVariantGroup section */
160 | 254405F724AFB44C00C32DC8 /* Main.storyboard */ = {
161 | isa = PBXVariantGroup;
162 | children = (
163 | 254405F824AFB44C00C32DC8 /* Base */,
164 | );
165 | name = Main.storyboard;
166 | sourceTree = "";
167 | };
168 | 254405FC24AFB44E00C32DC8 /* LaunchScreen.storyboard */ = {
169 | isa = PBXVariantGroup;
170 | children = (
171 | 254405FD24AFB44E00C32DC8 /* Base */,
172 | );
173 | name = LaunchScreen.storyboard;
174 | sourceTree = "";
175 | };
176 | /* End PBXVariantGroup section */
177 |
178 | /* Begin XCBuildConfiguration section */
179 | 2544060024AFB44E00C32DC8 /* Debug */ = {
180 | isa = XCBuildConfiguration;
181 | buildSettings = {
182 | ALWAYS_SEARCH_USER_PATHS = NO;
183 | CLANG_ANALYZER_NONNULL = YES;
184 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
185 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
186 | CLANG_CXX_LIBRARY = "libc++";
187 | CLANG_ENABLE_MODULES = YES;
188 | CLANG_ENABLE_OBJC_ARC = YES;
189 | CLANG_ENABLE_OBJC_WEAK = YES;
190 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
191 | CLANG_WARN_BOOL_CONVERSION = YES;
192 | CLANG_WARN_COMMA = YES;
193 | CLANG_WARN_CONSTANT_CONVERSION = YES;
194 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
195 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
196 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
197 | CLANG_WARN_EMPTY_BODY = YES;
198 | CLANG_WARN_ENUM_CONVERSION = YES;
199 | CLANG_WARN_INFINITE_RECURSION = YES;
200 | CLANG_WARN_INT_CONVERSION = YES;
201 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
202 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
203 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
204 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
205 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
206 | CLANG_WARN_STRICT_PROTOTYPES = YES;
207 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
208 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
209 | CLANG_WARN_UNREACHABLE_CODE = YES;
210 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
211 | COPY_PHASE_STRIP = NO;
212 | DEBUG_INFORMATION_FORMAT = dwarf;
213 | ENABLE_STRICT_OBJC_MSGSEND = YES;
214 | ENABLE_TESTABILITY = YES;
215 | GCC_C_LANGUAGE_STANDARD = gnu11;
216 | GCC_DYNAMIC_NO_PIC = NO;
217 | GCC_NO_COMMON_BLOCKS = YES;
218 | GCC_OPTIMIZATION_LEVEL = 0;
219 | GCC_PREPROCESSOR_DEFINITIONS = (
220 | "DEBUG=1",
221 | "$(inherited)",
222 | );
223 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
224 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
225 | GCC_WARN_UNDECLARED_SELECTOR = YES;
226 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
227 | GCC_WARN_UNUSED_FUNCTION = YES;
228 | GCC_WARN_UNUSED_VARIABLE = YES;
229 | IPHONEOS_DEPLOYMENT_TARGET = 13.5;
230 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
231 | MTL_FAST_MATH = YES;
232 | ONLY_ACTIVE_ARCH = YES;
233 | SDKROOT = iphoneos;
234 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
235 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
236 | };
237 | name = Debug;
238 | };
239 | 2544060124AFB44E00C32DC8 /* Release */ = {
240 | isa = XCBuildConfiguration;
241 | buildSettings = {
242 | ALWAYS_SEARCH_USER_PATHS = NO;
243 | CLANG_ANALYZER_NONNULL = YES;
244 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
245 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
246 | CLANG_CXX_LIBRARY = "libc++";
247 | CLANG_ENABLE_MODULES = YES;
248 | CLANG_ENABLE_OBJC_ARC = YES;
249 | CLANG_ENABLE_OBJC_WEAK = YES;
250 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
251 | CLANG_WARN_BOOL_CONVERSION = YES;
252 | CLANG_WARN_COMMA = YES;
253 | CLANG_WARN_CONSTANT_CONVERSION = YES;
254 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
255 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
256 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
257 | CLANG_WARN_EMPTY_BODY = YES;
258 | CLANG_WARN_ENUM_CONVERSION = YES;
259 | CLANG_WARN_INFINITE_RECURSION = YES;
260 | CLANG_WARN_INT_CONVERSION = YES;
261 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
262 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
263 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
264 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
265 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
266 | CLANG_WARN_STRICT_PROTOTYPES = YES;
267 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
268 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
269 | CLANG_WARN_UNREACHABLE_CODE = YES;
270 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
271 | COPY_PHASE_STRIP = NO;
272 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
273 | ENABLE_NS_ASSERTIONS = NO;
274 | ENABLE_STRICT_OBJC_MSGSEND = YES;
275 | GCC_C_LANGUAGE_STANDARD = gnu11;
276 | GCC_NO_COMMON_BLOCKS = YES;
277 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
278 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
279 | GCC_WARN_UNDECLARED_SELECTOR = YES;
280 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
281 | GCC_WARN_UNUSED_FUNCTION = YES;
282 | GCC_WARN_UNUSED_VARIABLE = YES;
283 | IPHONEOS_DEPLOYMENT_TARGET = 13.5;
284 | MTL_ENABLE_DEBUG_INFO = NO;
285 | MTL_FAST_MATH = YES;
286 | SDKROOT = iphoneos;
287 | SWIFT_COMPILATION_MODE = wholemodule;
288 | SWIFT_OPTIMIZATION_LEVEL = "-O";
289 | VALIDATE_PRODUCT = YES;
290 | };
291 | name = Release;
292 | };
293 | 2544060324AFB44E00C32DC8 /* Debug */ = {
294 | isa = XCBuildConfiguration;
295 | buildSettings = {
296 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
297 | CODE_SIGN_STYLE = Automatic;
298 | DEVELOPMENT_TEAM = "";
299 | INFOPLIST_FILE = WKWebViewDownloadHelper/Info.plist;
300 | LD_RUNPATH_SEARCH_PATHS = (
301 | "$(inherited)",
302 | "@executable_path/Frameworks",
303 | );
304 | PRODUCT_BUNDLE_IDENTIFIER = gfrigerio.com.WKWebViewDownloadHelper;
305 | PRODUCT_NAME = "$(TARGET_NAME)";
306 | SWIFT_VERSION = 5.0;
307 | TARGETED_DEVICE_FAMILY = "1,2";
308 | };
309 | name = Debug;
310 | };
311 | 2544060424AFB44E00C32DC8 /* Release */ = {
312 | isa = XCBuildConfiguration;
313 | buildSettings = {
314 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
315 | CODE_SIGN_STYLE = Automatic;
316 | DEVELOPMENT_TEAM = "";
317 | INFOPLIST_FILE = WKWebViewDownloadHelper/Info.plist;
318 | LD_RUNPATH_SEARCH_PATHS = (
319 | "$(inherited)",
320 | "@executable_path/Frameworks",
321 | );
322 | PRODUCT_BUNDLE_IDENTIFIER = gfrigerio.com.WKWebViewDownloadHelper;
323 | PRODUCT_NAME = "$(TARGET_NAME)";
324 | SWIFT_VERSION = 5.0;
325 | TARGETED_DEVICE_FAMILY = "1,2";
326 | };
327 | name = Release;
328 | };
329 | /* End XCBuildConfiguration section */
330 |
331 | /* Begin XCConfigurationList section */
332 | 254405E924AFB44C00C32DC8 /* Build configuration list for PBXProject "WKWebViewDownloadHelper" */ = {
333 | isa = XCConfigurationList;
334 | buildConfigurations = (
335 | 2544060024AFB44E00C32DC8 /* Debug */,
336 | 2544060124AFB44E00C32DC8 /* Release */,
337 | );
338 | defaultConfigurationIsVisible = 0;
339 | defaultConfigurationName = Release;
340 | };
341 | 2544060224AFB44E00C32DC8 /* Build configuration list for PBXNativeTarget "WKWebViewDownloadHelper" */ = {
342 | isa = XCConfigurationList;
343 | buildConfigurations = (
344 | 2544060324AFB44E00C32DC8 /* Debug */,
345 | 2544060424AFB44E00C32DC8 /* Release */,
346 | );
347 | defaultConfigurationIsVisible = 0;
348 | defaultConfigurationName = Release;
349 | };
350 | /* End XCConfigurationList section */
351 |
352 | /* Begin XCRemoteSwiftPackageReference section */
353 | 258F07062674DAF6003DC7EF /* XCRemoteSwiftPackageReference "WKDownloadHelper" */ = {
354 | isa = XCRemoteSwiftPackageReference;
355 | repositoryURL = "https://github.com/gualtierofrigerio/WKDownloadHelper";
356 | requirement = {
357 | kind = upToNextMajorVersion;
358 | minimumVersion = 0.2.3;
359 | };
360 | };
361 | /* End XCRemoteSwiftPackageReference section */
362 |
363 | /* Begin XCSwiftPackageProductDependency section */
364 | 258F07072674DAF6003DC7EF /* WKDownloadHelper */ = {
365 | isa = XCSwiftPackageProductDependency;
366 | package = 258F07062674DAF6003DC7EF /* XCRemoteSwiftPackageReference "WKDownloadHelper" */;
367 | productName = WKDownloadHelper;
368 | };
369 | /* End XCSwiftPackageProductDependency section */
370 | };
371 | rootObject = 254405E624AFB44C00C32DC8 /* Project object */;
372 | }
373 |
--------------------------------------------------------------------------------