1. 啟用 Sign in with Apple
選擇項(xiàng)目 TARGETS -> Signing&Capabilities 晰韵,單擊下圖中的 3:Capability:
在彈出框中搜索找到 Sign in with Apple:
然后,雙擊,即可啟用Apple 登錄:
點(diǎn)擊右側(cè)的x验夯,可以關(guān)閉 Apple 登錄哟沫。
最后饥追,登錄開發(fā)者中心哨苛,在需要啟用 Sign in with Apple 的 Apple ID中勾選 Sign in with Apple:
這些完成后幢码,我們就可以在項(xiàng)目中使用相關(guān)的功能了。
2. 添加代碼
在需要使用 login with Apple 的地方奏甫,引入頭文件:
#import <AuthenticationServices/AuthenticationServices.h>
首先戈轿,我們需要一個登錄按鈕,系統(tǒng)為我們預(yù)設(shè)了一個固定樣式登錄按鈕ASAuthorizationAppleIDButton
阵子,我們可以這樣使用它:
ASAuthorizationAppleIDButton *button = [ASAuthorizationAppleIDButton buttonWithType:(ASAuthorizationAppleIDButtonTypeSignIn) style:(ASAuthorizationAppleIDButtonStyleBlack)];
[button addTarget:self action:@selector(buttonAction:) forControlEvents:(UIControlEventTouchUpInside)];
button.frame = CGRectMake(60, 60, 200, 60);
[self.view addSubview:button];
這時思杯,按鈕的樣式是這樣的:
如果我們設(shè)置的按鈕是正方形,或者寬度不足以顯示文字挠进,將會出現(xiàn)一個只有蘋果logo的按鈕:
通過參數(shù) type色乾、style可以設(shè)置為不同樣式的按鈕;當(dāng)然领突,我們也可以自定義暖璧,但是要遵循蘋果的相關(guān)設(shè)計規(guī)范,詳見 Human Interface Guidelines君旦。
接下來就是需要添加授權(quán)的相關(guān)代碼了澎办;
3. 申請授權(quán)
在申請授權(quán)的過程中使用到的類都比較簡單:
//主要作用是用創(chuàng)建相應(yīng)的請求,查詢用戶授權(quán)狀態(tài)
ASAuthorizationAppleIDProvider
// 授權(quán)請求金砍,可以設(shè)置具體的請求信息
ASAuthorizationAppleIDRequest
// 發(fā)送請求控制器局蚀,可以設(shè)置相應(yīng)的協(xié)議
ASAuthorizationController
這其中使用到了兩個協(xié)議: ASAuthorizationControllerDelegate
ASAuthorizationControllerPresentationContextProviding
,前者用于接收請求成功或者失敗的回調(diào)捞魁;后者用于返回彈出請求框的window至会,一般返回當(dāng)前視圖window即可!
// ASAuthorizationControllerDelegate
// 成功的回調(diào)
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization NS_SWIFT_NAME(authorizationController(controller:didCompleteWithAuthorization:));
// 失敗的回調(diào)
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error NS_SWIFT_NAME(authorizationController(controller:didCompleteWithError:));
// ASAuthorizationControllerPresentationContextProviding
// 返回彈出請求視圖的window谱俭;
// ASPresentationAnchor 為 UIWindow 的別名:
// typedef UIWindow * ASPresentationAnchor;
- (ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller;
4. 發(fā)起授權(quán)
//基于用戶的Apple ID授權(quán)用戶奉件,生成用戶授權(quán)請求的一種機(jī)制
ASAuthorizationAppleIDProvider *provider = [[ASAuthorizationAppleIDProvider alloc]init];
// 創(chuàng)建請求
ASAuthorizationAppleIDRequest *req = [provider createRequest];
// 設(shè)置請求的信息
req.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];
// 創(chuàng)建管理授權(quán)請求的控制器
ASAuthorizationController *controller = [[ASAuthorizationController alloc]initWithAuthorizationRequests:@[req]];
// 設(shè)置代理
controller.delegate = self;
controller.presentationContextProvider = self;
// 發(fā)起請求
[controller performRequests];
然后實(shí)現(xiàn)相應(yīng)的代理協(xié)議:
// 授權(quán)失敗的回調(diào)
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error {
NSString *msg = @"未知";
switch (error.code) {
case ASAuthorizationErrorCanceled:
msg = @"用戶取消";
break;
case ASAuthorizationErrorFailed:
msg = @"授權(quán)請求失敗";
break;
case ASAuthorizationErrorInvalidResponse:
msg = @"授權(quán)請求無響應(yīng)";
break;
case ASAuthorizationErrorNotHandled:
msg = @"授權(quán)請求未處理";
break;
case ASAuthorizationErrorUnknown:
msg = @"授權(quán)失敗,原因未知";
break;
default:
break;
}
NSLog(@"%@", msg);
}
// 授權(quán)成功的回調(diào)
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization {
if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
ASAuthorizationAppleIDCredential *credential = authorization.credential;
//蘋果用戶唯一標(biāo)識符昆著,
// 該值在同一個開發(fā)者賬號下的所有 App 下是一樣的县貌,
//開發(fā)者可以用該唯一標(biāo)識符與自己后臺系統(tǒng)的賬號體系綁定起來。
NSString *user = credential.user;
// 獲取用戶名
NSString *familyName = credential.fullName.familyName;
NSString * givenName = credential.fullName.givenName;
// 獲取郵箱
NSString *email = credential.email;
// 獲取驗(yàn)證信息
// 驗(yàn)證數(shù)據(jù)凑懂,用于傳給開發(fā)者后臺服務(wù)器煤痕,
// 然后開發(fā)者服務(wù)器再向蘋果的身份驗(yàn)證服務(wù)端驗(yàn)證本次授權(quán)登錄請求數(shù)據(jù)的有效性和真實(shí)性,
// 如果驗(yàn)證成功接谨,可以根據(jù) userIdentifier 判斷賬號是否已存在摆碉,
// 若存在,則返回自己賬號系統(tǒng)的登錄態(tài)脓豪,若不存在巷帝,則創(chuàng)建一個新的賬號,并返回對應(yīng)的登錄態(tài)給 App扫夜。
NSData *identityToken = credential.identityToken;
NSData *code = credential.authorizationCode;
if (self.completeHander) {
self.completeHander(YES, user, familyName, givenName, email, nil, identityToken, code, nil, @"授權(quán)成功");
}
} else if ([authorization.credential isKindOfClass:[ASPasswordCredential class]]) {
// 使用現(xiàn)有的密碼憑證登錄
ASPasswordCredential *credential = authorization.credential;
// 用戶唯一標(biāo)識符
NSString *user = credential.user;
NSString *password = credential.password;
if (self.completeHander) {
self.completeHander(YES, user, nil, nil, nil, password, nil, nil, nil, @"授權(quán)成功");
}
}
}
- (ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller {
return [UIApplication sharedApplication].windows.firstObject;
}
點(diǎn)擊登錄后楞泼,如果是未授權(quán)會彈出如下彈框:
這里的郵件地址驰徊,用戶可以選擇共享或者隱藏,如果選擇了隱藏堕阔,開發(fā)者將會獲得一個蘋果自動生成的一個郵箱地址棍厂,而不是用戶的真實(shí)郵箱;成功后返回的信息如下:
user: 004673.27e48e27b0e5853a7c5d744d9a1c8725.0683
familyName: 劉
givenName: 流火緋瞳
email: c96fqxirwu@privaterelay.appleid.com
這里我選擇了隱藏郵箱超陆,返回的是蘋果生成的一個郵箱地址牺弹;
我們可以將 user 信息保存到keychain中,
如果我們已經(jīng)授權(quán)登錄成功侥猬,再次登錄的時候例驹,就會顯示如下的頁面:
如果把登錄的信息保存到Keychain,我們可以使用下面的方式進(jìn)行讀取密碼登錄:
ASAuthorizationAppleIDProvider *provider = [[ASAuthorizationAppleIDProvider alloc]init];
ASAuthorizationAppleIDRequest *req = [provider createRequest];
ASAuthorizationPasswordProvider *pasProvider = [[ASAuthorizationPasswordProvider alloc]init];
ASAuthorizationPasswordRequest *pasReq = [pasProvider createRequest];
NSMutableArray *arr = [NSMutableArray arrayWithCapacity:2];
if (req) {
[arr addObject:req];
}
if (pasReq) {
[arr addObject:pasReq];
}
ASAuthorizationController *controller = [[ASAuthorizationController alloc]initWithAuthorizationRequests:arr.copy];
controller.delegate = self;
controller.presentationContextProvider = self;
[controller performRequests];
這時獲取到的信息將只有user:
user: 004673.27e48e27b0e5853a7c5d744d9a1c8725.0683
familyName: (null)
givenName: (null)
email: (null)
app登錄成功后退唠,需要將獲取到的 identityToken
、code
等信息發(fā)送給后臺荤胁,然后由后臺調(diào)用 Apple 的后臺API瞧预,來驗(yàn)證用戶的真實(shí)性,從而完成驗(yàn)證仅政,詳情參考 Sign In With Apple 從登陸到服務(wù)器驗(yàn)證
5. 檢測登錄/授權(quán)狀態(tài)
登錄成功后垢油,用戶是可以隨時取消授權(quán)的,或者用戶將 AppleID退出了當(dāng)前設(shè)備圆丹,都需要重新獲忍渤睢;
我們可以在應(yīng)用啟動的時候使用下面的方法來檢測用戶狀態(tài):
// 使用 user 信息辫封,查詢當(dāng)前用戶的狀態(tài)
+ (void) checkAuthorizationStateWithUser:(NSString *) user
completeHandler:(void(^)(BOOL authorized, NSString *msg)) completeHandler {
if (user == nil || user.length <= 0) {
if (completeHandler) {
completeHandler(NO, @"用戶標(biāo)識符錯誤");
}
return;
}
ASAuthorizationAppleIDProvider *provider = [[ASAuthorizationAppleIDProvider alloc]init];
[provider getCredentialStateForUserID:user completion:^(ASAuthorizationAppleIDProviderCredentialState credentialState, NSError * _Nullable error) {
NSString *msg = @"未知";
BOOL authorized = NO;
switch (credentialState) {
case ASAuthorizationAppleIDProviderCredentialRevoked:
msg = @"授權(quán)被撤銷";
authorized = NO;
break;
case ASAuthorizationAppleIDProviderCredentialAuthorized:
msg = @"已授權(quán)";
authorized = YES;
break;
case ASAuthorizationAppleIDProviderCredentialNotFound:
msg = @"未查到授權(quán)信息";
authorized = NO;
break;
case ASAuthorizationAppleIDProviderCredentialTransferred:
msg = @"授權(quán)信息變動";
authorized = NO;
break;
default:
authorized = NO;
break;
}
if (completeHandler) {
completeHandler(authorized, msg);
}
}];
}
如果app在運(yùn)行中硝枉,我們可以通過添加通知的方法來實(shí)時監(jiān)控:
- (void) startAppleIDObserverWithCompleteHandler {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(lq_signWithAppleIDStateChanged:) name:ASAuthorizationAppleIDProviderCredentialRevokedNotification object:nil];
}
- (void) lq_signWithAppleIDStateChanged:(NSNotification *) noti {
NSLog(@"%@", noti.name);
NSLog(@"%@", noti.userInfo);
}
這里的 userInfo 信息一直都是 null,需要我們再次使用上面的方法去檢測授權(quán)狀態(tài)倦微,然后做出相應(yīng)的處理妻味。
6. 取消授權(quán)
對應(yīng)用授權(quán)登錄后,我們可以在設(shè)備中取消對某個app的授權(quán)欣福,操作方法如下:
設(shè)置 -> Apple ID -> 密碼與安全性 -> 使用您 Apple ID 的 App
打開后會顯示所有使用 Apple ID 進(jìn)行登錄的 App:
選擇需要取消的app责球,停止使用 Apple ID 即可!
7. 一些問題
Error Domain=com.apple.AuthenticationServices.AuthorizationError Code=1000 "
項(xiàng)目配置中未添加 Sign in with Apple
,參考文章第一步