source/UberCore/Deeplinks/DeeplinkManager.swift (51 lines of code) (raw):

// // DeeplinkManager.swift // UberCore // // Copyright © 2016 Uber Technologies, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. /** The Deeplink Manager keeps track of an external URL being opened. */ class DeeplinkManager { static let shared = DeeplinkManager() var urlOpener: URLOpening = UIApplication.shared private var urlQueue: [URL] = [] private var callback: DeeplinkCompletionHandler? /// Open a deeplink, utilizing its fallback URLs. func open(_ deeplink: Deeplinking, completion: DeeplinkCompletionHandler? = nil) { urlQueue = deeplink.fallbackURLs open(deeplink.url, completion: completion) } /// Open a URL func open(_ url: URL, completion: DeeplinkCompletionHandler? = nil) { callback = completion open(url) } //Mark: Internal Interface private func open(_ url: URL) { if urlOpener.canOpenURL(url) { urlOpener.open(url, completionHandler: { (succeeded) in if !succeeded { self.deeplinkDidFinish(error: DeeplinkErrorFactory.errorForType(.unableToFollow)) } else { self.deeplinkDidFinish(error: nil) } }) } else { deeplinkDidFinish(error: DeeplinkErrorFactory.errorForType(.unableToOpen)) } } private func deeplinkDidFinish(error: NSError?) { if error != nil && !urlQueue.isEmpty && error != DeeplinkErrorFactory.errorForType(.deeplinkNotFollowed) { // There is an error AND urlQueue is NOT empty. // Also, it's not a user cancelled deeplink. // Thus we will try opening the next url in the queue. open(urlQueue.removeFirst()) return } callback?(error) self.urlQueue = [] self.callback = nil } @objc private func deeplinkHelper() { let error = DeeplinkErrorFactory.errorForType(.deeplinkNotFollowed) deeplinkDidFinish(error: error) } } public protocol URLOpening { func canOpenURL(_ url: URL) -> Bool func open(_ url: URL, completionHandler: ((Bool) -> Void)?) } extension UIApplication: URLOpening { public func open(_ url: URL, completionHandler: ((Bool) -> Void)?) { open(url, options: [:], completionHandler: completionHandler) } }