公司項目需要接入sign in with Apple,花了幾天時間,查看各種文檔博客,最終完成接入。
客戶端接入遇到的一些問題
1.首次登錄時調用的代碼:
if (@available(iOS 13.0, *)) {
// 基於用戶的Apple ID授權用戶,生成用戶授權請求的一種機制
ASAuthorizationAppleIDProvider *appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init];
// 創建新的AppleID 授權請求
ASAuthorizationAppleIDRequest *appleIDRequest = [appleIDProvider createRequest];
// 在用戶授權期間請求的聯繫信息
appleIDRequest.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];
// 由ASAuthorizationAppleIDProvider創建的授權請求 管理授權請求的控制器
ASAuthorizationController *authorizationController = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[appleIDRequest]];
// 設置授權控制器通知授權請求的成功與失敗的代理
authorizationController.delegate = self;
// 設置提供 展示上下文的代理,在這個上下文中 系統可以展示授權界面給用戶
authorizationController.presentationContextProvider = self;
// 在控制器初始化期間啓動授權流
[authorizationController performRequests];
}else{
// 處理不支持系統版本
NSLog(@"該系統版本不可用Apple登錄");
}
2.已經授權過,再次登錄的時候,如果你已經開啓了Touch id或者Face ID,直接使用Touch id或者Face ID登錄,沒有開啓的話,使用密碼登錄,sign in Apple沒有自動登錄接口,如果自己項目中需要自動登錄功能,不考慮服務器驗證的情況下,可以使用自己的pid和token登錄,但是這會有一定的安全性,具體代碼如下:
if (@available(iOS 13.0, *)) {
// 基於用戶的Apple ID授權用戶,生成用戶授權請求的一種機制
ASAuthorizationAppleIDProvider *appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init];
// 授權請求AppleID
ASAuthorizationAppleIDRequest *appleIDRequest = [appleIDProvider createRequest];
// 爲了執行鑰匙串憑證分享生成請求的一種機制
ASAuthorizationPasswordProvider *passwordProvider = [[ASAuthorizationPasswordProvider alloc] init];
ASAuthorizationPasswordRequest *passwordRequest = [passwordProvider createRequest];
// 由ASAuthorizationAppleIDProvider創建的授權請求 管理授權請求的控制器
ASAuthorizationController *authorizationController = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[appleIDRequest, passwordRequest]];
// 設置授權控制器通知授權請求的成功與失敗的代理
authorizationController.delegate = self;
// 設置提供 展示上下文的代理,在這個上下文中 系統可以展示授權界面給用戶
authorizationController.presentationContextProvider = self;
// 在控制器初始化期間啓動授權流
[authorizationController performRequests];
}else{
// 處理不支持系統版本
NSLog(@"該系統版本不可用Apple登錄");
}
3.sign in Apple登錄授權成功回調的代碼,值得注意的是familyName ,givenName ,email 只有第一次登錄的時候纔有值,再次登錄返回都是空值;ASPasswordCredential 回調我是一直測試不出來,目前不知道怎樣登錄才能收到ASPasswordCredential 的回調,具體代碼如下:
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0)){
if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
ASAuthorizationAppleIDCredential *appleIDCredential = authorization.credential;
NSString *user = appleIDCredential.user;
NSString *state = appleIDCredential.state;
// 使用過授權的,可能獲取不到以下三個參數
NSString *familyName = appleIDCredential.fullName.familyName;
NSString *givenName = appleIDCredential.fullName.givenName;
NSString *email = appleIDCredential.email;
ASUserDetectionStatus realUserStatus = appleIDCredential.realUserStatus;
NSLog(@"familyName=%@", familyName);
NSLog(@"givenName=%@", givenName);
NSLog(@"email=%@", email);
NSLog(@"state=%@", state);
NSLog(@"user=%@", user);
if (user) {
[AppleKeychain save:KEYCHAIN_IDENTIFIER(@"userIdentifier") data:user];
}
NSLog(@"realUserStatus=%ld", (long)realUserStatus);
NSData *identityToken = appleIDCredential.identityToken;
NSData *authorizationCode = appleIDCredential.authorizationCode;
// 服務器驗證需要使用的參數
NSString *identityTokenStr = [[NSString alloc] initWithData:identityToken encoding:NSUTF8StringEncoding];
NSString *authorizationCodeStr = [[NSString alloc] initWithData:authorizationCode encoding:NSUTF8StringEncoding];
NSLog(@"%@\n\n%@", identityTokenStr, authorizationCodeStr);
if (identityTokenStr&&authorizationCodeStr) {
[self doLoginVerify:identityTokenStr AndCode:authorizationCodeStr];
}
}else if ([authorization.credential isKindOfClass:[ASPasswordCredential class]]){
// 這個獲取的是iCloud記錄的賬號密碼,需要輸入框支持iOS 12 記錄賬號密碼的新特性
//這個回調我是沒有測試出來過,不知道怎麼搞
// Sign in using an existing iCloud Keychain credential.
// 用戶登錄使用現有的密碼憑證
NSLog(@"Sign in using an existing iCloud Keychain credential");
ASPasswordCredential *passwordCredential = authorization.credential;
// 密碼憑證對象的用戶標識 用戶的唯一標識
NSString *user = passwordCredential.user;
// 密碼憑證對象的密碼
NSString *password = passwordCredential.password;
NSLog(@"user=%@", user);
NSLog(@"password=%@", password);
}else{
NSLog(@"授權信息均不符");
}
}
4.蘋果登錄觀察授權狀態監聽,如果你切換一個新的Apple id或者停止使用Apple id,那麼回調的結果是不一樣的,根據自己項目做處理,正常情況,你只要使用sign in Apple登錄過一次,那麼下次再登錄的時候,回調都是授權狀態良好,具體代碼如下:
if (@available(iOS 13.0, *)) {
// A mechanism for generating requests to authenticate users based on their Apple ID.
// 基於用戶的Apple ID 生成授權用戶請求的機制
ASAuthorizationAppleIDProvider *appleIDProvider = [ASAuthorizationAppleIDProvider new];
// 注意 存儲用戶標識信息需要使用鑰匙串來存儲 這裏筆者簡單期間 使用NSUserDefaults 做的簡單示例
NSString *userIdentifier = [AppleKeychain load:KEYCHAIN_IDENTIFIER(@"userIdentifier")];
NMGLog(@"observeAuthticationState----:%@",userIdentifier);
if (userIdentifier) {
NSString* __block errorMsg = nil;
//Returns the credential state for the given user in a completion handler.
// 在回調中返回用戶的授權狀態
[appleIDProvider getCredentialStateForUserID:userIdentifier completion:^(ASAuthorizationAppleIDProviderCredentialState credentialState, NSError * _Nullable error) {
switch (credentialState) {
// 蘋果證書的授權狀態
case ASAuthorizationAppleIDProviderCredentialRevoked:
// 蘋果授權憑證失效
errorMsg = @"蘋果授權憑證失效";
[self logout];
break;
case ASAuthorizationAppleIDProviderCredentialAuthorized:
// 蘋果授權憑證狀態良好
errorMsg = @"蘋果授權憑證狀態良好";
break;
case ASAuthorizationAppleIDProviderCredentialNotFound:
// 未發現蘋果授權憑證
errorMsg = @"未發現蘋果授權憑證";
[self logout];
break;
// 可以引導用戶重新登錄
case ASAuthorizationAppleIDProviderCredentialTransferred:
errorMsg = @"蘋果授權信息變動";
break;
}
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"SignInWithApple授權狀態變化情況");
NSLog(@"%@", errorMsg);
});
}];
}
}
5.能不能自定義sign in Apple按鈕這個問題,我們也發郵件去諮詢了蘋果公司,回覆的是:you best to use the familiar buttons that Apple provides for Sign in with Apple,但是最終我們沒有使用系統自帶的ASAuthorizationAppleIDButton ,而是按照設計規範自己設計按鈕。目前無法確定是否可以提審成功。
一些參考文檔:
https://developer.apple.com/design/human-interface-guidelines/sign-in-with-apple/overview/
https://developer.apple.com/documentation/signinwithapplerestapi/authenticating_users_with_sign_in_with_apple#see-also