diff --git a/IFTTT SDK/ConnectButton.swift b/IFTTT SDK/ConnectButton.swift index 43892dc..929b915 100644 --- a/IFTTT SDK/ConnectButton.swift +++ b/IFTTT SDK/ConnectButton.swift @@ -345,7 +345,7 @@ public class ConnectButton: UIView { footerLabel.constrain.edges(to: footerLabelContainer, edges: [.left, .top, .right]) // But allow it to be shorter than its container - footerLabel.bottomAnchor.constraint(lessThanOrEqualTo: footerLabelContainer.bottomAnchor) + footerLabel.bottomAnchor.constraint(lessThanOrEqualTo: footerLabelContainer.bottomAnchor).isActive = true let breakableBottomConstraint = footerLabel.bottomAnchor.constraint(equalTo: footerLabelContainer.bottomAnchor) breakableBottomConstraint.priority = .defaultHigh diff --git a/IFTTT SDK/SignInWithAppleAuthentication.swift b/IFTTT SDK/SignInWithAppleAuthentication.swift index a004503..fd175a2 100644 --- a/IFTTT SDK/SignInWithAppleAuthentication.swift +++ b/IFTTT SDK/SignInWithAppleAuthentication.swift @@ -41,6 +41,27 @@ final class AppleSignInWebService: ServiceAuthentication { @available(iOS 13.0, *) func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) { let authorizationError = ASAuthorizationError(_nsError: error as NSError) + // Cases added after the SDK's iOS 14.2 deployment target. + // Each is referenced behind an availability check and mapped + // to the matching AuthenticationError case so callers can + // distinguish it from the generic .failed / .unknown bucket. + if #available(iOS 15.4, *), authorizationError.code == .notInteractive { + completion(.failure(.notInteractive)) + return + } + if #available(iOS 18.0, *), authorizationError.code == .matchedExcludedCredential { + completion(.failure(.matchedExcludedCredential)) + return + } + if #available(iOS 18.2, *), authorizationError.code == .credentialImport { + completion(.failure(.credentialImport)) + return + } + if #available(iOS 18.2, *), authorizationError.code == .credentialExport { + completion(.failure(.credentialExport)) + return + } + switch authorizationError.code { case .canceled: completion(.failure(.userCanceled)) diff --git a/IFTTT SDK/WebServiceAuthentication.swift b/IFTTT SDK/WebServiceAuthentication.swift index c14863f..aa77c59 100644 --- a/IFTTT SDK/WebServiceAuthentication.swift +++ b/IFTTT SDK/WebServiceAuthentication.swift @@ -14,6 +14,15 @@ import AuthenticationServices /// - invalidResponse: The response returned by the web service was invalid. /// - notHandled: The error wasn't handled by the web service. /// - presentationContextInvalid: The presentation content provided was invalid. +/// - notInteractive: The authorization request was performed in a +/// non-interactive context. Mirrors `ASAuthorizationError.notInteractive` +/// (iOS 15.4+). +/// - matchedExcludedCredential: A matched credential was excluded from use. +/// Mirrors `ASAuthorizationError.matchedExcludedCredential` (iOS 18+). +/// - credentialImport: An error occurred importing a credential. Mirrors +/// `ASAuthorizationError.credentialImport` (iOS 18.2+). +/// - credentialExport: An error occurred exporting a credential. Mirrors +/// `ASAuthorizationError.credentialExport` (iOS 18.2+). /// - unknown: Some unknown error ocurred when authenticating with the web service. enum AuthenticationError: Error { case userCanceled @@ -21,6 +30,10 @@ enum AuthenticationError: Error { case invalidResponse case notHandled case presentationContextInvalid + case notInteractive + case matchedExcludedCredential + case credentialImport + case credentialExport case unknown }