From e506ceb25a5320ddc4a12e3da870c10bc9dc193d Mon Sep 17 00:00:00 2001 From: Riley Testut Date: Tue, 8 Sep 2020 16:42:25 -0700 Subject: [PATCH] Fixes opening deep links --- AltStore/SceneDelegate.swift | 82 ++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/AltStore/SceneDelegate.swift b/AltStore/SceneDelegate.swift index 602b6f8f..2249c1c5 100644 --- a/AltStore/SceneDelegate.swift +++ b/AltStore/SceneDelegate.swift @@ -20,6 +20,11 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). guard let _ = (scene as? UIWindowScene) else { return } + + if let context = connectionOptions.urlContexts.first + { + self.open(context) + } } func sceneWillEnterForeground(_ scene: UIScene) @@ -49,4 +54,81 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate ServerManager.shared.stopDiscovering() } + + func scene(_ scene: UIScene, openURLContexts URLContexts: Set) + { + guard let context = URLContexts.first else { return } + self.open(context) + } +} + +@available(iOS 13.0, *) +private extension SceneDelegate +{ + func open(_ context: UIOpenURLContext) + { + if context.url.isFileURL + { + guard context.url.pathExtension.lowercased() == "ipa" else { return } + + DispatchQueue.main.async { + NotificationCenter.default.post(name: AppDelegate.importAppDeepLinkNotification, object: nil, userInfo: [AppDelegate.importAppDeepLinkURLKey: context.url]) + } + } + else + { + guard let components = URLComponents(url: context.url, resolvingAgainstBaseURL: false) else { return } + guard let host = components.host?.lowercased() else { return } + + switch host + { + case "patreon": + DispatchQueue.main.async { + NotificationCenter.default.post(name: AppDelegate.openPatreonSettingsDeepLinkNotification, object: nil) + } + + case "appbackupresponse": + let result: Result + + switch context.url.path.lowercased() + { + case "/success": result = .success(()) + case "/failure": + let queryItems = components.queryItems?.reduce(into: [String: String]()) { $0[$1.name] = $1.value } ?? [:] + guard + let errorDomain = queryItems["errorDomain"], + let errorCodeString = queryItems["errorCode"], let errorCode = Int(errorCodeString), + let errorDescription = queryItems["errorDescription"] + else { return } + + let error = NSError(domain: errorDomain, code: errorCode, userInfo: [NSLocalizedDescriptionKey: errorDescription]) + result = .failure(error) + + default: return + } + + DispatchQueue.main.async { + NotificationCenter.default.post(name: AppDelegate.appBackupDidFinish, object: nil, userInfo: [AppDelegate.appBackupResultKey: result]) + } + + case "install": + let queryItems = components.queryItems?.reduce(into: [String: String]()) { $0[$1.name.lowercased()] = $1.value } ?? [:] + guard let downloadURLString = queryItems["url"], let downloadURL = URL(string: downloadURLString) else { return } + + DispatchQueue.main.async { + NotificationCenter.default.post(name: AppDelegate.importAppDeepLinkNotification, object: nil, userInfo: [AppDelegate.importAppDeepLinkURLKey: downloadURL]) + } + + case "source": + let queryItems = components.queryItems?.reduce(into: [String: String]()) { $0[$1.name.lowercased()] = $1.value } ?? [:] + guard let sourceURLString = queryItems["url"], let sourceURL = URL(string: sourceURLString) else { return } + + DispatchQueue.main.async { + NotificationCenter.default.post(name: AppDelegate.addSourceDeepLinkNotification, object: nil, userInfo: [AppDelegate.addSourceDeepLinkURLKey: sourceURL]) + } + + default: break + } + } + } }