Sign In with Apple 介绍
1 Sign in with Apple (苹果登录),苹果登录是 iOS13 新增加的功能,当你的应用使用了第三方登录比如微信登录,同时也需要集成苹果登录,否则提交审核可能会被拒绝
2 添加处都要添加iOS 13 的判断,可以自定义,也可以使用苹果自带的按钮展示样式,查看了几个大的APP,基本都是用的苹果自带的登录样式。(优先建议苹果自带样式)
3 对于 ASAuthorizationAppleIDButton 我们能够自定义的东西比较少,比如不能修改背景色,文案只有三种可以选择,可以调整的只有圆角 cornerRadius 和尺寸 size 。


登录按钮和自定义按钮
1 系统自带的按钮展示效果 3种文案

- 如果是准备自定义按钮的,请参考苹果自定义按钮的规则,免得审核被拒。
- 按钮必须在显著的位置(避免滑动屏幕才能看到)
- 登录按钮有三种外观:白色,带有黑色轮廓线的白色和黑色,其他设计可能会影响审核;
- 按钮圆角范围及按钮最小尺寸也有要求(官方文档);
2 xcode首先添加配置 (这里需要有一个注意的地方,如果过个targets,如果某一个targets有用的是企业证书,企业证书是没有苹果登录功能的,所有需要单独配置entitlements)

3 代码实现
// 导入头文件
#import <AuthenticationServices/AuthenticationServices.h>
ASAuthorizationAppleIDButton *loginBtn = [[ASAuthorizationAppleIDButton alloc]initWithAuthorizationButtonType:ASAuthorizationAppleIDButtonTypeSignIn authorizationButtonStyle:ASAuthorizationAppleIDButtonStyleWhiteOutline];
[loginBtn addTarget:self action:@selector(signInWithApple) forControlEvents:UIControlEventTouchUpInside];
loginBtn.frame = CGRectMake((SCREEN_WIDTH-200)/2, 0, 200, 40);
loginBtn.cornerRadius = 40/2;
[self addSubview:loginBtn];
- (void)signInWithApple{
if (@available(iOS 13.0, *)) {
ASAuthorizationAppleIDProvider * appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init];
ASAuthorizationAppleIDRequest * authAppleIDRequest = [appleIDProvider createRequest];
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];
ASAuthorizationController * authorizationController = [[ASAuthorizationController alloc] initWithAuthorizationRequests:requests];
authorizationController.delegate = self;
authorizationController.presentationContextProvider = self;
[authorizationController performRequests];
} else {
// 处理不支持系统版本
NSLog(@"系统不支持Apple登录");
}
}
后面设置爱2个代理
apple登录对于所有设备,比如iPhone、iPad、Mac,只要是同一个开发者账号的,同一个用户在所有软件中返回的openid都是相同的,类似于QQ登录和微信登录中的unionid
#pragma mark- ASAuthorizationControllerDelegate
// 授权成功
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization {
if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
//高能预警
//授权信息里的用户信息(email、NSPersonNameComponents对象所有属性)当且仅当第一次授权时才会返回,之后就算 停止使用 Apple ID 再重新授权都不会返回用户信息
ASAuthorizationAppleIDCredential * credential = authorization.credential;
// 苹果用户唯一标识符,该值在同一个开发者账号下的所有 App 下是一样的,开发者可以用该唯一标识符与自己后台系统的账号体系绑定起来。
NSString * userID = credential.user;
// 苹果用户信息 如果授权过,可能无法再次获取该信息
NSPersonNameComponents * fullName = credential.fullName;
NSString * email = credential.email;
// 服务器验证需要使用的参数
NSString * authorizationCode = [[NSString alloc] initWithData:credential.authorizationCode encoding:NSUTF8StringEncoding];
NSString * identityToken = [[NSString alloc] initWithData:credential.identityToken encoding:NSUTF8StringEncoding];
// 用于判断当前登录的苹果账号是否是一个真实用户,取值有:unsupported、unknown、likelyReal
ASUserDetectionStatus realUserStatus = credential.realUserStatus;
if (userID.length > 0) {
[GCSaveDataTool saveUserData:userID forKey:GCAppleIDNSUserDefaults];
}
// given name等同于first name是名,教名。如字面意思,父母或者教父给起的名字。
//
// middle name是名和姓之间的名字,是父母或亲戚所取,一般取长者的名或姓。
//
// familiy name是姓氏,家族名FAMILY是家庭的意思,姓是家庭共有的,可以这样理解。last name
//
// 解析
//
// 英语姓名的一般结构为:自取名+教名+姓。given name + familiy name
NSString *nickName;
if (!ZHStringIsEmpty(fullName.givenName) || !ZHStringIsEmpty(fullName.familyName)) {
nickName = [NSString stringWithFormat:@"%@%@",fullName.givenName,fullName.familyName];
}
if (!ZHStringIsEmpty(nickName)) {
[GCSaveDataTool saveUserData:nickName forKey:GCAppleFullNameNSUserDefaults];
}
NSLog(@"userID: %@ familyName %@", userID,fullName.familyName);
NSLog(@"nickName: %@", nickName);
NSLog(@"email: %@", email);
NSLog(@"authorizationCode: %@", authorizationCode);
NSLog(@"identityToken: %@", identityToken);
NSLog(@"realUserStatus: %@", @(realUserStatus));
if (self.authorizationBlock) {
self.authorizationBlock(YES, userID);
}
}
}
// 授权失败
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error {
NSString *errorMsg = nil;
switch (error.code) {
case ASAuthorizationErrorCanceled:
errorMsg = @"用户取消了授权请求";
break;
case ASAuthorizationErrorFailed:
errorMsg = @"授权请求失败";
break;
case ASAuthorizationErrorInvalidResponse:
errorMsg = @"授权请求响应无效";
break;
case ASAuthorizationErrorNotHandled:
errorMsg = @"未能处理授权请求";
break;
case ASAuthorizationErrorUnknown:
errorMsg = @"授权请求失败未知原因";
break;
}
}
#pragma mark- ASAuthorizationControllerPresentationContextProviding
//ASAuthorizationControllerPresentationContextProviding 主要是告诉 ASAuthorizationController 在哪个 window 上显示。
- (ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller {
return self.view.window;
}
具体注意事项
1用户注销 AppleId 或 停止使用 Apple ID 的状态处理 这个里面需要监测appid 的状态,处理一些业务逻辑。但是我发现这里没有什么可处理的业务逻辑,所以我只没有写,如果大家有写的,可以一起讨论下
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
if (@available(iOS 13.0, *)) {
// 注意 存储用户标识信息需要使用钥匙串来存储 这里使用NSUserDefaults 做的简单示例
NSString * userIdentifier = [[NSUserDefaults standardUserDefaults] valueForKey:@"appleID"];
if (userIdentifier) {
ASAuthorizationAppleIDProvider * appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init];
[appleIDProvider getCredentialStateForUserID:userIdentifier
completion:^(ASAuthorizationAppleIDProviderCredentialState credentialState, NSError * _Nullable error) {
switch (credentialState) {
case ASAuthorizationAppleIDProviderCredentialAuthorized:
// 授权状态有效
break;
case ASAuthorizationAppleIDProviderCredentialRevoked:
// 苹果账号登录的凭据已被移除,需解除绑定并重新引导用户使用苹果登录
break;
case ASAuthorizationAppleIDProviderCredentialNotFound:
// 未登录授权,直接弹出登录页面,引导用户登录
break;
case ASAuthorizationAppleIDProviderCredentialTransferred:
// 授权AppleID提供者凭据转移
break;
}
}];
}
}
return YES;
}
2 还有一个通知的监测(这个我也没有做处理,不知道有做处理的吗)
// 注册通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleSignInWithAppleStateChanged:) name:ASAuthorizationAppleIDProviderCredentialRevokedNotification object:nil];
#pragma mark- apple授权状态 更改通知
- (void)handleSignInWithAppleStateChanged:(NSNotification *)notification
{
NSLog(@"%@", notification.userInfo);
}