--- /dev/null
+//
+// OAuthSwiftURLHandlerType.swift
+// OAuthSwift
+//
+// Created by phimage on 11/05/15.
+// Copyright (c) 2015 Dongri Jin. All rights reserved.
+//
+
+import Foundation
+
+#if os(iOS) || os(tvOS)
+ import UIKit
+#elseif os(watchOS)
+ import WatchKit
+#elseif os(OSX)
+ import AppKit
+#endif
+
+@objc public protocol OAuthSwiftURLHandlerType {
+ func handle(_ url: URL)
+}
+
+// MARK: Open externally
+open class OAuthSwiftOpenURLExternally: OAuthSwiftURLHandlerType {
+
+ public static var sharedInstance: OAuthSwiftOpenURLExternally = OAuthSwiftOpenURLExternally()
+
+ @objc open func handle(_ url: URL) {
+ #if os(iOS) || os(tvOS)
+ #if !OAUTH_APP_EXTENSIONS
+ UIApplication.shared.openURL(url)
+ #endif
+ #elseif os(watchOS)
+ // WATCHOS: not implemented
+ #elseif os(OSX)
+ NSWorkspace.shared.open(url)
+ #endif
+ }
+}
+
+// MARK: Open SFSafariViewController
+#if os(iOS)
+import SafariServices
+
+ @available(iOS 9.0, *)
+ open class SafariURLHandler: NSObject, OAuthSwiftURLHandlerType, SFSafariViewControllerDelegate {
+
+ public typealias UITransion = (_ controller: SFSafariViewController, _ handler: SafariURLHandler) -> Void
+
+ weak open var oauthSwift: OAuthSwift?
+ open var present: UITransion
+ open var dismiss: UITransion
+ /// retains observers
+ var observers = [String: NSObjectProtocol]()
+
+ open var factory: (_ URL: URL) -> SFSafariViewController = {URL in
+ return SFSafariViewController(url: URL)
+ }
+
+ /// delegates
+ open weak var delegate: SFSafariViewControllerDelegate?
+
+ // configure default presentation and dismissal code
+
+ open var animated: Bool = true
+ open var presentCompletion: (() -> Void)?
+ open var dismissCompletion: (() -> Void)?
+ open var delay: UInt32? = 1
+
+ /// init
+ public init(viewController: UIViewController, oauthSwift: OAuthSwift) {
+ self.oauthSwift = oauthSwift
+ self.present = { [weak viewController] controller, handler in
+ viewController?.present(controller, animated: handler.animated, completion: handler.presentCompletion)
+ }
+ self.dismiss = { [weak viewController] _, handler in
+ viewController?.dismiss(animated: handler.animated, completion: handler.dismissCompletion)
+ }
+ }
+
+ public init(present: @escaping UITransion, dismiss: @escaping UITransion, oauthSwift: OAuthSwift) {
+ self.oauthSwift = oauthSwift
+ self.present = present
+ self.dismiss = dismiss
+ }
+
+ @objc open func handle(_ url: URL) {
+ let controller = factory(url)
+ controller.delegate = self
+
+ // present controller in main thread
+ OAuthSwift.main { [weak self] in
+ guard let this = self else {
+ return
+ }
+ if let delay = this.delay { // sometimes safari show a blank view..
+ sleep(delay)
+ }
+ this.present(controller, this)
+ }
+
+ let key = UUID().uuidString
+
+ observers[key] = OAuthSwift.notificationCenter.addObserver(
+ forName: NSNotification.Name.OAuthSwiftHandleCallbackURL,
+ object: nil,
+ queue: OperationQueue.main,
+ using: { [weak self] _ in
+ guard let this = self else {
+ return
+ }
+ if let observer = this.observers[key] {
+ OAuthSwift.notificationCenter.removeObserver(observer)
+ this.observers.removeValue(forKey: key)
+ }
+ OAuthSwift.main {
+ this.dismiss(controller, this)
+ }
+ }
+ )
+ }
+
+ /// Clear internal observers on authentification flow
+ open func clearObservers() {
+ clearLocalObservers()
+ self.oauthSwift?.removeCallbackNotificationObserver()
+ }
+
+ open func clearLocalObservers() {
+ for (_, observer) in observers {
+ OAuthSwift.notificationCenter.removeObserver(observer)
+ }
+ observers.removeAll()
+ }
+
+ /// SFSafariViewControllerDelegate
+ public func safariViewController(_ controller: SFSafariViewController, activityItemsFor URL: Foundation.URL, title: String?) -> [UIActivity] {
+ return self.delegate?.safariViewController?(controller, activityItemsFor: URL, title: title) ?? []
+ }
+
+ public func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
+ // "Done" pressed
+ self.clearObservers()
+ self.delegate?.safariViewControllerDidFinish?(controller)
+ }
+
+ public func safariViewController(_ controller: SFSafariViewController, didCompleteInitialLoad didLoadSuccessfully: Bool) {
+ self.delegate?.safariViewController?(controller, didCompleteInitialLoad: didLoadSuccessfully)
+ }
+
+ }
+
+#endif
+
+// MARK: Open url using NSExtensionContext
+open class ExtensionContextURLHandler: OAuthSwiftURLHandlerType {
+
+ fileprivate var extensionContext: NSExtensionContext
+
+ public init(extensionContext: NSExtensionContext) {
+ self.extensionContext = extensionContext
+ }
+
+ @objc open func handle(_ url: URL) {
+ extensionContext.open(url, completionHandler: nil)
+ }
+}