Skip to content

Commit a0706c1

Browse files
added fix do allow open url InAppBrowser and download a file
1 parent 1e0b419 commit a0706c1

File tree

2 files changed

+86
-2
lines changed

2 files changed

+86
-2
lines changed

Sources/OSInAppBrowserLib/Models/OSIABWebViewConfigurationModel.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@ struct OSIABWebViewConfigurationModel {
3636
configuration.ignoresViewportScaleLimits = ignoresViewportScaleLimits
3737
configuration.allowsInlineMediaPlayback = allowsInlineMediaPlayback
3838
configuration.suppressesIncrementalRendering = suppressesIncrementalRendering
39+
let windowOpenScript = WKUserScript(
40+
source: """
41+
window.open = function(url, target, features) {
42+
if (url) { window.location.href = url; }
43+
};
44+
""",
45+
injectionTime: .atDocumentStart,
46+
forMainFrameOnly: false
47+
)
48+
configuration.userContentController.addUserScript(windowOpenScript)
3949
return configuration
4050
}
4151
}

Sources/OSInAppBrowserLib/WebView/OSIABWebViewModel.swift

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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
236310
extension OSIABWebViewModel: WKUIDelegate {
237311
typealias ButtonHandler = (UIAlertController) -> Void

0 commit comments

Comments
 (0)