diff --git a/Simplicity.xcodeproj/project.pbxproj b/Simplicity.xcodeproj/project.pbxproj index 14421cd..5d705d1 100644 --- a/Simplicity.xcodeproj/project.pbxproj +++ b/Simplicity.xcodeproj/project.pbxproj @@ -151,12 +151,12 @@ DF74EC271CE2A8BB008F16BF /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0800; + LastUpgradeCheck = 0930; ORGANIZATIONNAME = Stormpath; TargetAttributes = { DF74EC2F1CE2A8BB008F16BF = { CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 0800; + LastSwiftMigration = 0930; }; }; }; @@ -165,6 +165,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, ); mainGroup = DF74EC261CE2A8BB008F16BF; @@ -218,14 +219,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -270,14 +279,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -324,7 +341,8 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -344,7 +362,8 @@ PRODUCT_BUNDLE_IDENTIFIER = com.stormpath.Simplicity; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 5.0; }; name = Release; }; diff --git a/Simplicity.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Simplicity.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Simplicity.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Simplicity.xcodeproj/xcshareddata/xcschemes/Simplicity.xcscheme b/Simplicity.xcodeproj/xcshareddata/xcschemes/Simplicity.xcscheme index 6d0e049..3748824 100644 --- a/Simplicity.xcodeproj/xcshareddata/xcschemes/Simplicity.xcscheme +++ b/Simplicity.xcodeproj/xcshareddata/xcschemes/Simplicity.xcscheme @@ -1,6 +1,6 @@ Bool) -> [String] { + // Retrieve url types from the main bundle guard let urlTypes = Bundle.main.infoDictionary?["CFBundleURLTypes"] as? [[String: AnyObject]] else { return [String]() } // Convert the complex dictionary into an array of URL schemes - let urlSchemes = urlTypes.flatMap({($0["CFBundleURLSchemes"] as? [String])?.first }) + let urlSchemes: [String] = urlTypes.reduce(into: []) { (result, component) in + if let schemes = component["CFBundleURLSchemes"] as? [String] { + result.append(contentsOf: schemes) + } + } - return urlSchemes.flatMap({closure($0) ? $0 : nil}) + // Filter schemes with parameter block + return urlSchemes.compactMap({closure($0) ? $0 : nil}) } /** @@ -36,7 +42,7 @@ class Helpers { - returns: A query string */ static func queryString(_ parts: [String: String?]) -> String? { - return parts.flatMap { key, value -> String? in + return parts.compactMap { key, value -> String? in if let value = value { return key + "=" + value } else { diff --git a/Simplicity/LoginProviders/Facebook.swift b/Simplicity/LoginProviders/Facebook.swift index 1bea523..f5a85db 100644 --- a/Simplicity/LoginProviders/Facebook.swift +++ b/Simplicity/LoginProviders/Facebook.swift @@ -38,7 +38,12 @@ public class Facebook: OAuth2 { /// An array with query string parameters for the authorization URL. override public var authorizationURLParameters: [String : String?] { var result = super.authorizationURLParameters + // Required parameters to have the button to connect via the native fb app result["auth_type"] = authType.rawValue + result["display"] = "touch" + result["sdk"] = "ios" + result["fbapp_pres"] = "1" + result["sdk_version"] = "4.31.1" return result } @@ -53,7 +58,7 @@ public class Facebook: OAuth2 { let range = urlScheme.range(of: "\\d+", options: .regularExpression) else { preconditionFailure("You must configure your Facebook URL Scheme to use Facebook login.") } - let clientId = urlScheme.substring(with: range) + let clientId = String(urlScheme[range.lowerBound.. URLQueryItem? in + url.queryItems = authorizationURLParameters.compactMap({key, value -> URLQueryItem? in return value != nil ? URLQueryItem(name: key, value: value) : nil }) diff --git a/Simplicity/Simplicity.swift b/Simplicity/Simplicity.swift index 347a888..f668cee 100644 --- a/Simplicity/Simplicity.swift +++ b/Simplicity/Simplicity.swift @@ -12,43 +12,61 @@ import SafariServices /// Callback handler after an external login completes. public typealias ExternalLoginCallback = (String?, NSError?) -> Void -/** +/** Simplicity is a framework for authenticating with external providers on iOS. */ public final class Simplicity { private static var currentLoginProvider: LoginProvider? private static var callback: ExternalLoginCallback? private static var safari: UIViewController? + @available(iOS 11.0, *) + private static var authSession: SFAuthenticationSession? /** Begin the login flow by redirecting to the LoginProvider's website. - parameters: - - loginProvider: The login provider object configured to be used. - - callback: A callback with the access token, or a SimplicityError. + - loginProvider: The login provider object configured to be used. + - callback: A callback with the access token, or a SimplicityError. */ public static func login(_ loginProvider: LoginProvider, callback: @escaping ExternalLoginCallback) { self.currentLoginProvider = loginProvider self.callback = callback - presentSafariView(loginProvider.authorizationURL) + if #available(iOS 11, *) { + if self.presentAuthentificationSession(url: loginProvider.authorizationURL, callbackURL: loginProvider.urlScheme) == false { + self.presentSafariView(loginProvider.authorizationURL) + } + } else { + self.presentSafariView(loginProvider.authorizationURL) + } } /// Deep link handler (iOS9) - public static func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey: Any]) -> Bool { - safari?.dismiss(animated: true, completion: nil) - guard let callback = callback, url.scheme == currentLoginProvider?.urlScheme else { - return false + public static func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any]) -> Bool { + if let safari = self.safari { + safari.dismiss(animated: true, completion: nil) + self.safari = nil } - currentLoginProvider?.linkHandler(url, callback: callback) - currentLoginProvider = nil + if #available(iOS 11.0, *) { + if let auth = self.authSession { + auth.cancel() + self.authSession = nil + } + } + guard let callback = self.callback, + let currentLoginProvider = self.currentLoginProvider, + url.scheme == currentLoginProvider.urlScheme + else { return false } + currentLoginProvider.linkHandler(url, callback: callback) + self.currentLoginProvider = nil return true } /// Deep link handler ( Bool { - return self.application(application, open: url, options: [UIApplicationOpenURLOptionsKey: Any]()) + return self.application(application, open: url, options: [UIApplication.OpenURLOptionsKey: Any]()) } private static func presentSafariView(_ url: URL) { @@ -63,4 +81,18 @@ public final class Simplicity { UIApplication.shared.openURL(url) } } + + @available(iOS 11.0, *) + private static func presentAuthentificationSession(url: URL, callbackURL: String) -> Bool { + + let session = SFAuthenticationSession(url: url, callbackURLScheme: nil) { (url, error) in + self.authSession = nil + if let url = url { + _ = self.application(UIApplication.shared, open: url, options: [:]) + } + } + self.authSession = session + return session.start() + + } }