@@ -19,6 +19,12 @@ class OSIABWebViewModel: NSObject, ObservableObject {
1919
2020 /// Indicates if first load is already done. This is important in order to trigger the `browserPageLoad` event.
2121 private var firstLoadDone : Bool = false
22+ /// Indicates if a download is in progress, to suppress navigation errors caused by download redirects.
23+ private var isDownloadInProgress : Bool = false
24+ /// Retains the active WKDownload to prevent it from being deallocated mid-download.
25+ private var activeDownload : AnyObject ?
26+ /// Stores the destination URL for the active download.
27+ private var downloadDestinationURL : URL ?
2228
2329 /// Custom headers to be used by the WebView.
2430 private let customHeaders : [ String : String ] ?
@@ -206,6 +212,18 @@ extension OSIABWebViewModel: WKNavigationDelegate {
206212 }
207213 }
208214
215+ @available ( iOS 14 . 5 , * )
216+ func webView( _ webView: WKWebView , navigationAction: WKNavigationAction , didBecome download: WKDownload ) {
217+ download. delegate = self
218+ }
219+
220+ @available ( iOS 14 . 5 , * )
221+ func webView( _ webView: WKWebView , navigationResponse: WKNavigationResponse , didBecome download: WKDownload ) {
222+ isDownloadInProgress = true
223+ activeDownload = download
224+ download. delegate = self
225+ }
226+
209227 func webView( _ webView: WKWebView , didFinish navigation: WKNavigation ! ) {
210228 if !firstLoadDone {
211229 callbackHandler. onBrowserPageLoad ( )
@@ -225,13 +243,69 @@ extension OSIABWebViewModel: WKNavigationDelegate {
225243 }
226244
227245 private func handleWebViewNavigationError( _ delegateName: String , error: Error ) {
228- print ( " webView: \( delegateName) - \( error. localizedDescription) " )
229- if ( error as NSError ) . code != NSURLErrorCancelled {
246+ let nsError = error as NSError
247+ if isDownloadInProgress && nsError. code == 102 {
248+ isDownloadInProgress = false
249+ return
250+ }
251+ if nsError. code != NSURLErrorCancelled {
230252 self . error = error
231253 }
232254 }
233255}
234256
257+ // MARK: - WKNavigationDelegate (response) implementation
258+ extension OSIABWebViewModel {
259+ func webView( _ webView: WKWebView , decidePolicyFor navigationResponse: WKNavigationResponse , decisionHandler: @escaping ( WKNavigationResponsePolicy ) -> Void ) {
260+ if navigationResponse. canShowMIMEType {
261+ decisionHandler ( . allow)
262+ } else {
263+ if #available( iOS 14 . 5 , * ) {
264+ decisionHandler ( . download)
265+ } else {
266+ decisionHandler ( . cancel)
267+ }
268+ }
269+ }
270+ }
271+
272+ // MARK: - WKDownloadDelegate implementation
273+ @available ( iOS 14 . 5 , * )
274+ extension OSIABWebViewModel : WKDownloadDelegate {
275+
276+ func download( _ download: WKDownload , decideDestinationUsing response: URLResponse , suggestedFilename: String , completionHandler: @escaping ( URL ? ) -> Void ) {
277+ let tempDir = FileManager . default. temporaryDirectory
278+ let fileURL = tempDir. appendingPathComponent ( suggestedFilename)
279+ if FileManager . default. fileExists ( atPath: fileURL. path) {
280+ try ? FileManager . default. removeItem ( at: fileURL)
281+ }
282+ downloadDestinationURL = fileURL
283+ completionHandler ( fileURL)
284+ }
285+
286+ func downloadDidFinish( _ download: WKDownload ) {
287+ guard let fileURL = downloadDestinationURL else { return }
288+ activeDownload = nil
289+ DispatchQueue . main. async {
290+ let activityVC = UIActivityViewController ( activityItems: [ fileURL] , applicationActivities: nil )
291+ if let rootVC = UIApplication . shared. connectedScenes
292+ . compactMap ( { $0 as? UIWindowScene } )
293+ . flatMap ( { $0. windows } )
294+ . first ( where: { $0. isKeyWindow } ) ? . rootViewController {
295+ var topVC = rootVC
296+ while let presented = topVC. presentedViewController {
297+ topVC = presented
298+ }
299+ topVC. present ( activityVC, animated: true )
300+ }
301+ }
302+ }
303+
304+ func download( _ download: WKDownload , didFailWithError error: Error , resumeData: Data ? ) {
305+ activeDownload = nil
306+ }
307+ }
308+
235309// MARK: - WKUIDelegate implementation
236310extension OSIABWebViewModel : WKUIDelegate {
237311 typealias ButtonHandler = ( UIAlertController ) -> Void
0 commit comments