闲话少说,直接上码
一. 开启Sign in with Apple 功能
1. app bundle id 开启Sign in with Apple
登陆developer账号,在app bundle ID的Capabilities里,打勾Sign In with Apple
.
2. Xcode里开启Sign in with Apple
打开Xcode 11.0 Beta或更新版本,在项目设置 -> Signing & Capabilities 里,开启Sign in with Apple
选项。
二. 实现
实现分四大部分:
- 创建
Sign in with Apple
Button. - 跟用户提出授权请求.
- 根据用户的授权来验证用户.
- 处理用户授权变更.
1. 创建Sign in with Apple
Button
import UIKit
import AuthenticationServices
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let button = ASAuthorizationAppleIDButton()
button.addTarget(self, action: #selector(handleAuthorization), for: .touchUpInside)
// `handleAuthorization`的实现参阅:2. 跟用户提出授权请求.
// 创建好button后,可以安装需求安装到所需的位置, 比如 self.view.addSubview(button)
}
}
2. 跟用户提出授权请求.
-
handleAuthorization
里主要是跟用户提出用苹果登陆请求,并要求用户提供用户名和email. - 发出请求需要创建
ASAuthorizationController
, 但是需要提供delegate
和presentationContextProvider
.-
ASAuthorizationControllerDelegate
会提供请求后的结果回调,比如用户请求失败,或者用户请求成功。 -
presentationContextProvider
是为验证的用户界面提供所需的window
.
-
@objc private func handleAuthorization() {
if #available(iOS 13.0, *) {
let requestID = ASAuthorizationAppleIDProvider().createRequest()
// 这里请求了用户的姓名和email
requestID.requestedScopes = [.fullName, .email]
let controller = ASAuthorizationController(authorizationRequests: [requestID])
controller.delegate = self
controller.presentationContextProvider = self
controller.performRequests()
} else {
// iOS13以前的版本不支持, 用户界面可以提示
}
}
@available(iOS 13.0, *)
extension ViewController: ASAuthorizationControllerDelegate
{
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
// 请求完成,但是有错误
}
func authorizationController(controller: ASAuthorizationController,
didCompleteWithAuthorization authorization: ASAuthorization)
{
// 请求完成, 用户通过验证
if let credential = authorization.credential as? ASAuthorizationAppleIDCredential
{
// 拿到用户的验证信息,这里可以跟自己服务器所存储的信息进行校验,比如用户名是否存在等。
let detailVC = DetailVC(cred: credential)
self.present(detailVC, animated: true, completion: nil)
}
}
}
@available(iOS 13.0, *)
extension ViewController: ASAuthorizationControllerPresentationContextProviding
{
func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
return (UIApplication.shared.delegate as! AppDelegate).window!
}
}
3. 根据用户的授权来验证用户.
if let credential = authorization.credential as? ASAuthorizationAppleIDCredential
在上面ASAuthorizationControllerDelegate
的用户通过验证的回调里,可以拿到credential
,这里面有一些信息值得提下:
- 用户emai:
credential.email
- 用户名信息:
credential.fullName
- 苹果提供的用户ID:
credential.user
- 验证信息状态:
credential.state
- refresh token:
let code = credential.authorizationCode, let codeStr = String(data: code, encoding: .utf8)
- access token:
let idToken = credential.identityToken, let tokeStr = String(data: idToken, encoding: .utf8)
4. 处理用户授权/用户信息变更.
授权或者用户信息是有可能被改变的,我们能做到就是尽早的检测出这样的改变,并做以应对。
检测授权的状态需要记录在上面所得到的
“苹果提供的用户ID:
credential.user
”
在AppleDelegate
里,把之前存的用户ID放到ASAuthorizationAppleIDProvider
里验证即可,可以得到几种用户授权状态:
-
authorized
: 授权合格/合法 -
revoked
:授权被撤销,用户可以在iOS系统设置了手动撤销授权。 -
notFound
:授权未找到
class AppDelegate: UIResponder, UIApplicationDelegate
{
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if let userID = Keychain.getSavedUserID() {
let appleIDProvider = ASAuthorizationAppleIDProvider()
appleIDProvider.getCredentialState(forUserID: "") { (state, error) in
switch state
{
case .authorized: // 处理合法的授权
break
case .revoked: // 处理被撤销的授权
break
case .notFound: //处理没有找到的授权
break
default: // 其他
break
}
}
}
return true
}
}
如果有错误欢迎指出,也欢迎各种讨论,谢🙏!