Skip to content

Build for MacOS 10.14 #436

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,93 +8,71 @@ import Flutter

let methodChannelName = "com.aboutyou.dart_packages.sign_in_with_apple"

@available(iOS 13.0, macOS 10.15, *)
// No @available is needed here since we will conditionally handle OS versions
public class SignInWithAppleAvailablePlugin: NSObject, FlutterPlugin {
var _lastSignInWithAppleAuthorizationController: SignInWithAppleAuthorizationController?

// This plugin should not be registered with directly
//
// This is merely a cross-platform plugin to handle the case Sign in with Apple is available
// on the target platform
//
// Each target platform will still need a specific Plugin implementation
// which will need to decide whether or not Sign in with Apple is available
// Wrap the variable in an availability check to prevent errors
var _lastSignInWithAppleAuthorizationController: Any?

public static func register(with registrar: FlutterPluginRegistrar) {
print("SignInWithAppleAvailablePlugin tried to register which is not allowed")
}

public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "isAvailable":
result(true)

if #available(iOS 13.0, macOS 10.15, *) {
result(true)
} else {
result(false)
}

case "performAuthorizationRequest":
// Makes sure arguments exists and is a List
// Ensure arguments exist and is a List
guard let args = call.arguments as? [Any] else {
result(
SignInWithAppleGenericError.missingArguments(call).toFlutterError()
)
result(SignInWithAppleGenericError.missingArguments(call).toFlutterError())
return
}

let signInController = SignInWithAppleAuthorizationController(result)

// store to keep alive
_lastSignInWithAppleAuthorizationController = signInController

signInController.performRequests(
requests: SignInWithAppleAuthorizationController.parseRequests(
rawRequests: args
)
)
// Only proceed if macOS 10.15 or newer is available
if #available(iOS 13.0, macOS 10.15, *) {
let signInController = SignInWithAppleAuthorizationController(result)
// Safely cast to avoid errors on macOS 10.14
_lastSignInWithAppleAuthorizationController = signInController

case "getCredentialState":
// Makes sure arguments exists and is a Map
guard let args = call.arguments as? [String: Any] else {
result(
SignInWithAppleGenericError.missingArguments(call).toFlutterError()
signInController.performRequests(
requests: SignInWithAppleAuthorizationController.parseRequests(rawRequests: args)
)
return
} else {
result(FlutterError(code: "UNSUPPORTED_OS", message: "macOS 10.15 or higher is required for Sign in with Apple", details: nil))
}

guard let userIdentifier = args["userIdentifier"] as? String else {
result(
SignInWithAppleGenericError.missingArgument(
call,
"userIdentifier"
).toFlutterError()
)
case "getCredentialState":
guard let args = call.arguments as? [String: Any], let userIdentifier = args["userIdentifier"] as? String else {
result(SignInWithAppleGenericError.missingArgument(call, "userIdentifier").toFlutterError())
return
}

let appleIDProvider = ASAuthorizationAppleIDProvider()

appleIDProvider.getCredentialState(forUserID: userIdentifier) {
credentialState, error in
if let error = error {
result(
SignInWithAppleError
.credentialsError(error.localizedDescription)
.toFlutterError()
)
return
}
if #available(iOS 13.0, macOS 10.15, *) {
let appleIDProvider = ASAuthorizationAppleIDProvider()
appleIDProvider.getCredentialState(forUserID: userIdentifier) { credentialState, error in
if let error = error {
result(SignInWithAppleError.credentialsError(error.localizedDescription).toFlutterError())
return
}

switch credentialState {
case .authorized:
result("authorized")
case .revoked:
result("revoked")
case .notFound:
result("notFound")

default:
result(
SignInWithAppleError
.unexpectedCredentialsState(credentialState)
.toFlutterError()
)
switch credentialState {
case .authorized:
result("authorized")
case .revoked:
result("revoked")
case .notFound:
result("notFound")
default:
result(SignInWithAppleError.unexpectedCredentialsState(credentialState).toFlutterError())
}
}
} else {
result(FlutterError(code: "UNSUPPORTED_OS", message: "macOS 10.15 or higher is required for Sign in with Apple", details: nil))
}

default:
Expand All @@ -106,94 +84,71 @@ public class SignInWithAppleAvailablePlugin: NSObject, FlutterPlugin {
@available(iOS 13.0, macOS 10.15, *)
class SignInWithAppleAuthorizationController: NSObject, ASAuthorizationControllerDelegate {
var callback: FlutterResult

init(_ callback: @escaping FlutterResult) {
self.callback = callback
}

// Parses a list of json requests into the proper [ASAuthorizationRequest] type.
//
// The parsing itself tries to be as lenient as possible to recover gracefully from parsing errors.

public static func parseRequests(rawRequests: [Any]) -> [ASAuthorizationRequest] {
var requests: [ASAuthorizationRequest] = []

for request in rawRequests {
guard let requestMap = request as? [String: Any] else {
print("[SignInWithApplePlugin]: Request is not an object");
guard let requestMap = request as? [String: Any], let type = requestMap["type"] as? String else {
print("[SignInWithApplePlugin]: Invalid request format")
continue
}

guard let type = requestMap["type"] as? String else {
print("[SignInWithApplePlugin]: Request type is not an string");
continue
}

switch (type) {

switch type {
case "appleid":
let appleIDProvider = ASAuthorizationAppleIDProvider()
let appleIDRequest = appleIDProvider.createRequest()

if let nonce = requestMap["nonce"] as? String {
appleIDRequest.nonce = nonce;
appleIDRequest.nonce = nonce
}

if let state = requestMap["state"] as? String {
appleIDRequest.state = state;
appleIDRequest.state = state
}

if let scopes = requestMap["scopes"] as? [String] {
appleIDRequest.requestedScopes = []

for scope in scopes {
switch scope {
appleIDRequest.requestedScopes = scopes.compactMap {
switch $0 {
case "email":
appleIDRequest.requestedScopes?.append(.email)
return .email
case "fullName":
appleIDRequest.requestedScopes?.append(.fullName)
return .fullName
default:
print("[SignInWithApplePlugin]: Unknown scope for the Apple ID request: \(scope)");
continue;
print("[SignInWithApplePlugin]: Unknown scope: \($0)")
return nil
}
}
}

requests.append(appleIDRequest)
case "password":
let passwordProvider = ASAuthorizationPasswordProvider()
let passwordRequest = passwordProvider.createRequest()

requests.append(passwordRequest)
default:
print("[SignInWithApplePlugin]: Unknown request type: \(type)");
continue;
print("[SignInWithApplePlugin]: Unknown request type: \(type)")
}

}

return requests
}

public func performRequests(requests: [ASAuthorizationRequest]) {
let authorizationController = ASAuthorizationController(
authorizationRequests: requests
)

let authorizationController = ASAuthorizationController(authorizationRequests: requests)
authorizationController.delegate = self
authorizationController.performRequests()
}

private func parseData(data: Data?) -> String? {
if let data = data {
return String(decoding: data, as: UTF8.self)
}

return nil
return data.flatMap { String(decoding: $0, as: UTF8.self) }
}

public func authorizationController(
controller _: ASAuthorizationController,
didCompleteWithAuthorization authorization: ASAuthorization
) {
public func authorizationController(controller _: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
switch authorization.credential {
case let appleIDCredential as ASAuthorizationAppleIDCredential:
let result: [String: String?] = [
Expand All @@ -204,48 +159,28 @@ class SignInWithAppleAuthorizationController: NSObject, ASAuthorizationControlle
"email": appleIDCredential.email,
"identityToken": parseData(data: appleIDCredential.identityToken),
"authorizationCode": parseData(data: appleIDCredential.authorizationCode),
"state": appleIDCredential.state,
"state": appleIDCredential.state
]
callback(result)

case let passwordCredential as ASPasswordCredential:
let result: [String: String] = [
"type": "password",
"username": passwordCredential.user,
"password": passwordCredential.password,
"password": passwordCredential.password
]
callback(result)

default:
// Not getting any credentials would result in an error (didCompleteWithError)
callback(
SignInWithAppleError.unknownCredentials(
authorization.credential
).toFlutterError()
)
callback(SignInWithAppleError.unknownCredentials(authorization.credential).toFlutterError())
}
}

public func authorizationController(
controller _: ASAuthorizationController,
didCompleteWithError error: Error
) {
public func authorizationController(controller _: ASAuthorizationController, didCompleteWithError error: Error) {
if let error = error as? ASAuthorizationError {
callback(
SignInWithAppleError.authorizationError(
error.code,
error.localizedDescription
).toFlutterError()
)
callback(SignInWithAppleError.authorizationError(error.code, error.localizedDescription).toFlutterError())
} else {
print("[SignInWithApplePlugin]: Unknown authorization error \(error)")

callback(
SignInWithAppleError.authorizationError(
ASAuthorizationError.Code.unknown,
error.localizedDescription
).toFlutterError()
)
callback(SignInWithAppleError.authorizationError(ASAuthorizationError.Code.unknown, error.localizedDescription).toFlutterError())
}
}
}
Loading