AppleSignInCoordinator.swift
3.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
//
// AppleSignInCoordinator.swift
// Runner
//
// Created by 权海 on 2026/6/15.
//
import Foundation
import AuthenticationServices
enum PlatformHostApiError: LocalizedError {
case deallocated
case invalidAppleCredential
case invalidGoogleCredential
case missingPresentationAnchor
case missingGoogleIDToken
case mailComposerAlreadyPresented
var errorDescription: String? {
switch self {
case .deallocated:
return "PlatformHostApiImpl was released before the native request started."
case .invalidAppleCredential:
return "Apple sign-in did not return an Apple ID credential."
case .invalidGoogleCredential:
return "Google sign-in did not return a Google user."
case .missingPresentationAnchor:
return "Unable to find a window for native presentation."
case .missingGoogleIDToken:
return "Google sign-in did not return an ID token."
case .mailComposerAlreadyPresented:
return "A mail composer is already being presented."
}
}
}
final class AppleSignInCoordinator: NSObject, ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding {
private let presentationAnchor: ASPresentationAnchor
private let completion: (Result<AppleSignInModel?, Error>) -> Void
static func currentPresentationAnchor() -> ASPresentationAnchor? {
if let keyWindow = UIApplication.shared.connectedScenes
.compactMap({ $0 as? UIWindowScene })
.flatMap(\.windows)
.first(where: \.isKeyWindow) {
return keyWindow
}
return nil
}
init(presentationAnchor: ASPresentationAnchor, completion: @escaping (Result<AppleSignInModel?, Error>) -> Void) {
self.presentationAnchor = presentationAnchor
self.completion = completion
}
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
guard let credential = authorization.credential as? ASAuthorizationAppleIDCredential else {
completion(.failure(PlatformHostApiError.invalidAppleCredential))
return
}
let nickname = credential.fullName.flatMap {
let fullName = PersonNameComponentsFormatter.localizedString(from: $0, style: .medium)
return fullName.isEmpty ? nil : fullName
}
let identityToken = credential.identityToken.flatMap { String(data: $0, encoding: .utf8) }
completion(.success(AppleSignInModel(
userId: credential.user,
email: credential.email,
nickname: nickname,
identityToken: identityToken
)))
}
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
let nsError = error as NSError
if nsError.domain == ASAuthorizationError.errorDomain,
ASAuthorizationError.Code(rawValue: nsError.code) == .canceled {
completion(.success(nil))
return
}
completion(.failure(error))
}
func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
presentationAnchor
}
}