Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ struct OSIABWebViewConfigurationModel {
configuration.ignoresViewportScaleLimits = ignoresViewportScaleLimits
configuration.allowsInlineMediaPlayback = allowsInlineMediaPlayback
configuration.suppressesIncrementalRendering = suppressesIncrementalRendering
let windowOpenScript = WKUserScript(
source: """
window.open = function(url, target, features) {
if (url) { window.location.href = url; }
};
""",
injectionTime: .atDocumentStart,
forMainFrameOnly: false
)
configuration.userContentController.addUserScript(windowOpenScript)
return configuration
}
}
78 changes: 76 additions & 2 deletions Sources/OSInAppBrowserLib/WebView/OSIABWebViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ class OSIABWebViewModel: NSObject, ObservableObject {

/// Indicates if first load is already done. This is important in order to trigger the `browserPageLoad` event.
private var firstLoadDone: Bool = false
/// Indicates if a download is in progress, to suppress navigation errors caused by download redirects.
private var isDownloadInProgress: Bool = false
/// Retains the active WKDownload to prevent it from being deallocated mid-download.
private var activeDownload: AnyObject?
/// Stores the destination URL for the active download.
private var downloadDestinationURL: URL?

/// Custom headers to be used by the WebView.
private let customHeaders: [String: String]?
Expand Down Expand Up @@ -206,6 +212,18 @@ extension OSIABWebViewModel: WKNavigationDelegate {
}
}

@available(iOS 14.5, *)
func webView(_ webView: WKWebView, navigationAction: WKNavigationAction, didBecome download: WKDownload) {
download.delegate = self
}

@available(iOS 14.5, *)
func webView(_ webView: WKWebView, navigationResponse: WKNavigationResponse, didBecome download: WKDownload) {
isDownloadInProgress = true
activeDownload = download
download.delegate = self
}

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
if !firstLoadDone {
callbackHandler.onBrowserPageLoad()
Expand All @@ -225,13 +243,69 @@ extension OSIABWebViewModel: WKNavigationDelegate {
}

private func handleWebViewNavigationError(_ delegateName: String, error: Error) {
print("webView: \(delegateName) - \(error.localizedDescription)")
if (error as NSError).code != NSURLErrorCancelled {
let nsError = error as NSError
if isDownloadInProgress && nsError.code == 102 {
isDownloadInProgress = false
return
}
if nsError.code != NSURLErrorCancelled {
self.error = error
}
}
}

// MARK: - WKNavigationDelegate (response) implementation
extension OSIABWebViewModel {
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
if navigationResponse.canShowMIMEType {
decisionHandler(.allow)
} else {
if #available(iOS 14.5, *) {
decisionHandler(.download)
} else {
decisionHandler(.cancel)
}
}
}
}

// MARK: - WKDownloadDelegate implementation
@available(iOS 14.5, *)
extension OSIABWebViewModel: WKDownloadDelegate {

func download(_ download: WKDownload, decideDestinationUsing response: URLResponse, suggestedFilename: String, completionHandler: @escaping (URL?) -> Void) {
let tempDir = FileManager.default.temporaryDirectory
let fileURL = tempDir.appendingPathComponent(suggestedFilename)
if FileManager.default.fileExists(atPath: fileURL.path) {
try? FileManager.default.removeItem(at: fileURL)
}
downloadDestinationURL = fileURL
completionHandler(fileURL)
}

func downloadDidFinish(_ download: WKDownload) {
guard let fileURL = downloadDestinationURL else { return }
activeDownload = nil
DispatchQueue.main.async {
let activityVC = UIActivityViewController(activityItems: [fileURL], applicationActivities: nil)
if let rootVC = UIApplication.shared.connectedScenes
.compactMap({ $0 as? UIWindowScene })
.flatMap({ $0.windows })
.first(where: { $0.isKeyWindow })?.rootViewController {
var topVC = rootVC
while let presented = topVC.presentedViewController {
topVC = presented
}
topVC.present(activityVC, animated: true)
}
}
}

func download(_ download: WKDownload, didFailWithError error: Error, resumeData: Data?) {
activeDownload = nil
}
}

// MARK: - WKUIDelegate implementation
extension OSIABWebViewModel: WKUIDelegate {
typealias ButtonHandler = (UIAlertController) -> Void
Expand Down
Loading