閑話少說,直接上碼
一. 開啟Sign in with Apple 功能
1. app bundle id 開啟Sign in with Apple
登陸developer賬號,在app bundle ID的Capabilities里,打勾Sign In with Apple
.
打勾Sign in with Apple
2. Xcode里開啟Sign in with Apple
打開Xcode 11.0 Beta或更新版本,在項目設置 -> Signing & Capabilities 里,開啟Sign in with Apple
選項。
在Xcode中開啟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
}
}
如果有錯誤歡迎指出,也歡迎各種討論,謝??!