// // RAAppleIdManager.swift // ***** // // Created by baitongtong on 2020/11/5. // Copyright © 2020 hq. All rights reserved. // import UIKit import AuthenticationServices @available(iOS 13.0, *) class RAAppleIdManager: NSObject { static var shard = RAAppleIdManager() ///发起苹果登录 func loginWithApple(callBack:((_ result: Bool,_ info: [String: Any]?) -> ())?) { let appleIDProvide = ASAuthorizationAppleIDProvider() let appIDRequest = appleIDProvide.createRequest() appIDRequest.requestedScopes = [ASAuthorization.Scope.fullName,ASAuthorization.Scope.email] let authorizationController = ASAuthorizationController.init(authorizationRequests: [appIDRequest]) authorizationController.delegate = self authorizationController.presentationContextProvider = self authorizationController.performRequests() self.fetchAppleLogin = { status,dic in if let callBack = callBack { callBack(status,dic) } } } ///如果存在iCloud Keychain 凭证或者AppleID 凭证提示用户 func perfomExistingAccountSetupFlows() { let appleIDProvide = ASAuthorizationAppleIDProvider() let appIDRequest = appleIDProvide.createRequest() let passwordProvider = ASAuthorizationPasswordProvider() let passwordRequest = passwordProvider.createRequest() let authorizationController = ASAuthorizationController.init(authorizationRequests: [appIDRequest,passwordRequest]) authorizationController.delegate = self authorizationController.presentationContextProvider = self authorizationController.performRequests() } private func loginWithServer(user:String,token:String,code:String) { ///向你的服务器验证 ,验证通过即可登录 } var fetchAppleLogin:((_ result: Bool,_ info: [String: Any]?) -> ())? ///苹果称,该 API 的速度非常快,我们可以在 App 每次启动时调用,然后根据结果做相应的处理: func panduan() { let appleIDProvider = ASAuthorizationAppleIDProvider() appleIDProvider.getCredentialState(forUserID: "currentUserIdentifier") { (credentialState, error) in switch credentialState { ///authorized:登录状态有效; ///revoked:上次使用苹果账号登录的凭据已被移除,需退出解除绑定并重新引导使用苹果登录; ///notFound:未登录,直接显示开发者 App 的登录页面。 case .authorized: // The Apple ID credential is valid break case .revoked: // Apple ID Credential revoked, handle unlink break case .notFound: // Credential not found, show login UI break default: break } } } func listern() { // Register for revocation notification // let center = NotificationCenter.default // let name = NSNotification.Name.ASAuthorizationAppleIDProviderCredentialRevoked // let observer = center.addObserver(forName: name, object: nil, queue: nil) { (Notification) in // // Sign the user out, optionally guide them to sign in again // } } } @available(iOS 13.0, *) extension RAAppleIdManager : ASAuthorizationControllerDelegate,ASAuthorizationControllerPresentationContextProviding { func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) { if authorization.credential.isKind(of: ASAuthorizationAppleIDCredential.classForCoder()) { /// 用户登录使用ASAuthorizationAppleIDCredential let appleIDCredential = authorization.credential as! ASAuthorizationAppleIDCredential let userId = appleIDCredential.user /// 使用过授权的,可能获取不到以下三个参数 let familyName = appleIDCredential.fullName?.familyName ?? "" let givenName = appleIDCredential.fullName?.givenName ?? "" let email = appleIDCredential.email ?? "" let identityToken = appleIDCredential.identityToken ?? Data() // let authorizationCode = appleIDCredential.authorizationCode ?? Data() // 用于判断当前登录的苹果账号是否是一个真实用户,取值有:unsupported、unknown、likelyReal // let realUserStatus = appleIDCredential.realUserStatus // 服务器验证需要使用的参数 let info:[String: Any] = ["nickName":familyName + givenName,"thirdPartyOpenId": userId,"email": email,"token":identityToken] if let callBack = fetchAppleLogin { callBack(true,info) } }else if authorization.credential.isKind(of: ASPasswordCredential.classForCoder()) { /// 这个获取的是iCloud记录的账号密码,需要输入框支持iOS 12 记录账号密码的新特性,如果不支持,可以忽略 /// Sign in using an existing iCloud Keychain credential. /// 用户登录使用现有的密码凭证 let passworCreddential = authorization.credential as! ASPasswordCredential /// 密码凭证对象的用户标识 用户的唯一标识 let userId = passworCreddential.user /// 密码凭证对象的密码 ///let password = passworCreddential.password let info:[String: Any] = ["nickName":"","thirdPartyOpenId": userId,"email": "","token":""] if let callBack = fetchAppleLogin { callBack(true,info) } }else{ if let callBack = fetchAppleLogin { callBack(false,nil) } } } func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) { var errorStr : String? switch (error as NSError).code { case ASAuthorizationError.canceled.rawValue : errorStr = "用户取消了授权请求" case ASAuthorizationError.failed.rawValue : errorStr = "授权请求失败" case ASAuthorizationError.invalidResponse.rawValue : errorStr = "授权请求无响应" case ASAuthorizationError.notHandled.rawValue : errorStr = "未能处理授权请求" case ASAuthorizationError.unknown.rawValue : errorStr = "授权请求失败原因未知" default: break } if let str = errorStr { if let callBack = fetchAppleLogin { callBack(false,["error":str]) } } } func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor { return UIApplication.shared.windows.last ?? ASPresentationAnchor() } }