【官網(wǎng):通過(guò) Apple 登錄,讓登錄變得輕松簡(jiǎn)單可婶∩盅郑】
【iOS 蘋果授權(quán)登錄(Sign in with Apple)系列之原生篇】
前言
2019年蘋果推出 蘋果登錄(Sign in with Apple)方式燎斩,要求2020年4月之后APP如果使用第三方或社交登錄服務(wù)(如 Facebook杯活、谷歌匆帚、 Twitter、Linkedln或亞馬遜等)轩猩,必須向用戶提供“以蘋果賬號(hào)登錄”服務(wù)的選項(xiàng)卷扮。
如果滿足以下條件,則可以不用蘋果登錄方式:
- 應(yīng)用專門使用公司自己的帳戶設(shè)置和登錄系統(tǒng)均践。
- 應(yīng)用是教育,企業(yè)或商業(yè)應(yīng)用摩幔,要求用戶使用現(xiàn)有的教育或企業(yè)帳戶登錄彤委。
- 應(yīng)用程序使用政府或行業(yè)支持的公民身份識(shí)別系統(tǒng)或電子ID來(lái)對(duì)用戶進(jìn)行身份驗(yàn)證。
- 應(yīng)用是特定第三方服務(wù)的客戶端或衡,要求用戶直接登錄其郵件焦影,社交媒體或其他第三方帳戶才能訪問(wèn)其內(nèi)容。
官網(wǎng)詳細(xì)規(guī)則
集成流程
一封断、準(zhǔn)備工作
1.最低要求手機(jī)iOS系統(tǒng)ios13.0斯辰,蘋果電腦系統(tǒng)macos(10.15),開發(fā)工具Xcode11
- 登錄蘋果開發(fā)者賬號(hào)后臺(tái)坡疼,找到應(yīng)用的BundleId, 點(diǎn)擊進(jìn)去查看詳情信息, 開啟 Sign in with Apple 功能彬呻。
-
Xcode 里面 Signing & Capabilities 添加 Sign in with Apple 功能。
Xcode添加 Sign in with Apple.png
二柄瑰、代碼集成(本流程比較簡(jiǎn)單,自定義的按鈕,沒(méi)有服務(wù)器驗(yàn)證流程)
因?yàn)槭亲远x的按鈕 沒(méi)有用蘋果系統(tǒng)自己的按鈕 ASAuthorizationAppleIDButton 闸氮,ASAuthorizationAppleIDButton
尺寸會(huì)有一些限制,還得處理本地化語(yǔ)言。
1.導(dǎo)入頭文件教沾,添加代理
#import <AuthenticationServices/AuthenticationServices.h>
<ASAuthorizationControllerDelegate,ASAuthorizationControllerPresentationContextProviding>
2.viewDidLoad 方法中 判斷手機(jī)系統(tǒng)版本 注冊(cè)通知
// 手機(jī)系統(tǒng)版本 不支持 時(shí) 隱藏蘋果登錄按鈕
if (@available(iOS 13.0, *)) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleSignInWithAppleStateChanged:) name:ASAuthorizationAppleIDProviderCredentialRevokedNotification object:nil];
} else {
self.appleLoginBtn.hidden = YES;
}
- 自定義的 蘋果登錄按鈕 的點(diǎn)擊事件中 處理
[self authorizationAppleID];
- 蘋果授權(quán)方法
#pragma mark- 授權(quán)蘋果ID
- (void)authorizationAppleID{
if (@available(iOS 13.0, *)) {
// 基于用戶的Apple ID授權(quán)用戶蒲跨,生成用戶授權(quán)請(qǐng)求的一種機(jī)制
ASAuthorizationAppleIDProvider * appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init];
// 創(chuàng)建新的AppleID 授權(quán)請(qǐng)求
ASAuthorizationAppleIDRequest * authAppleIDRequest = [appleIDProvider createRequest];
// 在用戶授權(quán)期間請(qǐng)求的聯(lián)系信息
// authAppleIDRequest.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];
//如果 KeyChain 里面也有登錄信息的話,可以直接使用里面保存的用戶名和密碼進(jìn)行登錄授翻。
// ASAuthorizationPasswordRequest * passwordRequest = [[[ASAuthorizationPasswordProvider alloc] init] createRequest];
NSMutableArray <ASAuthorizationRequest *> * array = [NSMutableArray arrayWithCapacity:2];
if (authAppleIDRequest) {
[array addObject:authAppleIDRequest];
}
// if (passwordRequest) {
// [array addObject:passwordRequest];
// }
NSArray <ASAuthorizationRequest *> * requests = [array copy];
// 由ASAuthorizationAppleIDProvider創(chuàng)建的授權(quán)請(qǐng)求 管理授權(quán)請(qǐng)求的控制器
ASAuthorizationController * authorizationController = [[ASAuthorizationController alloc] initWithAuthorizationRequests:requests];
// 設(shè)置授權(quán)控制器通知授權(quán)請(qǐng)求的成功與失敗的代理
authorizationController.delegate = self;
// 設(shè)置提供 展示上下文的代理或悲,在這個(gè)上下文中 系統(tǒng)可以展示授權(quán)界面給用戶
authorizationController.presentationContextProvider = self;
// 在控制器初始化期間啟動(dòng)授權(quán)流
[authorizationController performRequests];
}
}
- 實(shí)現(xiàn)代理方法 授權(quán)成功 獲取 用戶的唯一標(biāo)識(shí) 傳給后臺(tái) 判斷該用戶是否綁定手機(jī)號(hào),如果綁定了直接登錄堪唐,如果沒(méi)綁定跳綁定手機(jī)號(hào)頁(yè)面
#pragma mark- ASAuthorizationControllerDelegate
// 授權(quán)成功
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0)) {
if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
ASAuthorizationAppleIDCredential * credential = (ASAuthorizationAppleIDCredential *)authorization.credential;
// 蘋果用戶唯一標(biāo)識(shí)符巡语,該值在同一個(gè)開發(fā)者賬號(hào)下的所有 App 下是一樣的,開發(fā)者可以用該唯一標(biāo)識(shí)符與自己后臺(tái)系統(tǒng)的賬號(hào)體系綁定起來(lái)羔杨。
NSString * userID = credential.user;
//把用戶的唯一標(biāo)識(shí) 傳給后臺(tái) 判斷該用戶是否綁定手機(jī)號(hào)捌臊,如果綁定了直接登錄,如果沒(méi)綁定跳綁定手機(jī)號(hào)頁(yè)面
// // 蘋果用戶信息 如果授權(quán)過(guò)兜材,可能無(wú)法再次獲取該信息
// NSPersonNameComponents * fullName = credential.fullName;
// NSString * email = credential.email;
//
// // 服務(wù)器驗(yàn)證需要使用的參數(shù)
// NSString * authorizationCode = [[NSString alloc] initWithData:credential.authorizationCode encoding:NSUTF8StringEncoding];
// NSString * identityToken = [[NSString alloc] initWithData:credential.identityToken encoding:NSUTF8StringEncoding];
//
// // 用于判斷當(dāng)前登錄的蘋果賬號(hào)是否是一個(gè)真實(shí)用戶理澎,取值有:unsupported逞力、unknown、likelyReal
// ASUserDetectionStatus realUserStatus = credential.realUserStatus;
// NSLog(@"userID: %@", userID);
// NSLog(@"fullName: %@", fullName);
// NSLog(@"email: %@", email);
// NSLog(@"authorizationCode: %@", authorizationCode);
// NSLog(@"identityToken: %@", identityToken);
// NSLog(@"realUserStatus: %@", @(realUserStatus));
}else if ([authorization.credential isKindOfClass:[ASPasswordCredential class]]) {
// 這個(gè)獲取的是iCloud記錄的賬號(hào)密碼糠爬,需要輸入框支持iOS 12 記錄賬號(hào)密碼的新特性寇荧,如果不支持,可以忽略
// 用戶登錄使用現(xiàn)有的密碼憑證
ASPasswordCredential * passwordCredential = (ASPasswordCredential *)authorization.credential;
// 密碼憑證對(duì)象的用戶標(biāo)識(shí) 用戶的唯一標(biāo)識(shí)
NSString * user = passwordCredential.user;
//把用戶的唯一標(biāo)識(shí) 傳給后臺(tái) 判斷該用戶是否綁定手機(jī)號(hào)执隧,如果綁定了直接登錄揩抡,如果沒(méi)綁定跳綁定手機(jī)號(hào)頁(yè)面
// // 密碼憑證對(duì)象的密碼
// NSString * password = passwordCredential.password;
// NSLog(@"userID: %@", user);
// NSLog(@"password: %@", password);
} else {
}
}
// 授權(quán)失敗
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error API_AVAILABLE(ios(13.0)) {
NSString *errorMsg = nil;
switch (error.code) {
case ASAuthorizationErrorCanceled:
errorMsg = @"用戶取消了授權(quán)請(qǐng)求";
break;
case ASAuthorizationErrorFailed:
errorMsg = @"授權(quán)請(qǐng)求失敗";
break;
case ASAuthorizationErrorInvalidResponse:
errorMsg = @"授權(quán)請(qǐng)求響應(yīng)無(wú)效";
break;
case ASAuthorizationErrorNotHandled:
errorMsg = @"未能處理授權(quán)請(qǐng)求";
break;
case ASAuthorizationErrorUnknown:
errorMsg = @"授權(quán)請(qǐng)求失敗未知原因";
break;
}
NSLog(@"%@", errorMsg);
}
#pragma mark- ASAuthorizationControllerPresentationContextProviding
- (ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller API_AVAILABLE(ios(13.0)){
return self.view.window;
}
#pragma mark- apple授權(quán)狀態(tài) 更改通知
- (void)handleSignInWithAppleStateChanged:(NSNotification *)notification{
NSLog(@"%@", notification.userInfo);
}
- (void)dealloc {
if (@available(iOS 13.0, *)) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:ASAuthorizationAppleIDProviderCredentialRevokedNotification object:nil];
}
}
注意事項(xiàng)
1、首次登錄會(huì)返回所有參數(shù)镀琉,包括全名峦嗤、郵箱等(如果玩家登錄時(shí)拒絕提供真實(shí)的郵箱賬號(hào),蘋果會(huì)生成虛擬的郵箱賬號(hào))屋摔,二次登錄只會(huì)返回 UserID 和 授權(quán)碼烁设,其它信息不再返回!
2钓试、同一個(gè)開發(fā)者賬號(hào)下所有APP装黑,同一個(gè)apple id登陸時(shí),獲取的UserID 是一樣的弓熏。
3恋谭、兩個(gè)開發(fā)者賬號(hào)下的應(yīng)用,同一個(gè)apple id登陸時(shí)挽鞠,獲取的 UserID 不一樣
4疚颊、NSNotification.Name.ASAuthorizationAppleIDProviderCredentialRevoked, 系統(tǒng)在蘋果賬號(hào)登出時(shí)通知滞谢,此時(shí)應(yīng)用如果是蘋果登陸的用戶串稀,有沒(méi)有必要也登出賬號(hào)?
5狮杨、如果打開登錄界面時(shí)母截,設(shè)備的 iCloud Keychain 有 apple id 賬號(hào)可用時(shí),可以彈窗讓用戶選擇 iCloud Keychain 里的賬號(hào)來(lái)進(jìn)行登陸橄教。