2 // OAuthSwiftURLHandlerType.swift
5 // Created by phimage on 11/05/15.
6 // Copyright (c) 2015 Dongri Jin. All rights reserved.
11 #if os(iOS) || os(tvOS)
19 @objc public protocol OAuthSwiftURLHandlerType {
20 func handle(_ url: URL)
23 // MARK: Open externally
24 open class OAuthSwiftOpenURLExternally: OAuthSwiftURLHandlerType {
26 public static var sharedInstance: OAuthSwiftOpenURLExternally = OAuthSwiftOpenURLExternally()
28 @objc open func handle(_ url: URL) {
29 #if os(iOS) || os(tvOS)
30 #if !OAUTH_APP_EXTENSIONS
31 UIApplication.shared.openURL(url)
34 // WATCHOS: not implemented
36 NSWorkspace.shared.open(url)
41 // MARK: Open SFSafariViewController
45 @available(iOS 9.0, *)
46 open class SafariURLHandler: NSObject, OAuthSwiftURLHandlerType, SFSafariViewControllerDelegate {
48 public typealias UITransion = (_ controller: SFSafariViewController, _ handler: SafariURLHandler) -> Void
50 weak open var oauthSwift: OAuthSwift?
51 open var present: UITransion
52 open var dismiss: UITransion
54 var observers = [String: NSObjectProtocol]()
56 open var factory: (_ URL: URL) -> SFSafariViewController = {URL in
57 return SFSafariViewController(url: URL)
61 open weak var delegate: SFSafariViewControllerDelegate?
63 // configure default presentation and dismissal code
65 open var animated: Bool = true
66 open var presentCompletion: (() -> Void)?
67 open var dismissCompletion: (() -> Void)?
68 open var delay: UInt32? = 1
71 public init(viewController: UIViewController, oauthSwift: OAuthSwift) {
72 self.oauthSwift = oauthSwift
73 self.present = { [weak viewController] controller, handler in
74 viewController?.present(controller, animated: handler.animated, completion: handler.presentCompletion)
76 self.dismiss = { [weak viewController] _, handler in
77 viewController?.dismiss(animated: handler.animated, completion: handler.dismissCompletion)
81 public init(present: @escaping UITransion, dismiss: @escaping UITransion, oauthSwift: OAuthSwift) {
82 self.oauthSwift = oauthSwift
83 self.present = present
84 self.dismiss = dismiss
87 @objc open func handle(_ url: URL) {
88 let controller = factory(url)
89 controller.delegate = self
91 // present controller in main thread
92 OAuthSwift.main { [weak self] in
93 guard let this = self else {
96 if let delay = this.delay { // sometimes safari show a blank view..
99 this.present(controller, this)
102 let key = UUID().uuidString
104 observers[key] = OAuthSwift.notificationCenter.addObserver(
105 forName: NSNotification.Name.OAuthSwiftHandleCallbackURL,
107 queue: OperationQueue.main,
108 using: { [weak self] _ in
109 guard let this = self else {
112 if let observer = this.observers[key] {
113 OAuthSwift.notificationCenter.removeObserver(observer)
114 this.observers.removeValue(forKey: key)
117 this.dismiss(controller, this)
123 /// Clear internal observers on authentification flow
124 open func clearObservers() {
125 clearLocalObservers()
126 self.oauthSwift?.removeCallbackNotificationObserver()
129 open func clearLocalObservers() {
130 for (_, observer) in observers {
131 OAuthSwift.notificationCenter.removeObserver(observer)
133 observers.removeAll()
136 /// SFSafariViewControllerDelegate
137 public func safariViewController(_ controller: SFSafariViewController, activityItemsFor URL: Foundation.URL, title: String?) -> [UIActivity] {
138 return self.delegate?.safariViewController?(controller, activityItemsFor: URL, title: title) ?? []
141 public func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
143 self.clearObservers()
144 self.delegate?.safariViewControllerDidFinish?(controller)
147 public func safariViewController(_ controller: SFSafariViewController, didCompleteInitialLoad didLoadSuccessfully: Bool) {
148 self.delegate?.safariViewController?(controller, didCompleteInitialLoad: didLoadSuccessfully)
155 // MARK: Open url using NSExtensionContext
156 open class ExtensionContextURLHandler: OAuthSwiftURLHandlerType {
158 fileprivate var extensionContext: NSExtensionContext
160 public init(extensionContext: NSExtensionContext) {
161 self.extensionContext = extensionContext
164 @objc open func handle(_ url: URL) {
165 extensionContext.open(url, completionHandler: nil)