1、配置app套餐的Identifiers支持Sign In With Apple
如下图
2、项目配置
3、集成代码
主要步骤:
-
使用ASAuthorizationAppleIDButton创建button,布局,添加点击事件;
-
实现点击事件:授权请求
-
授权代理实现(授权成功,授权失败)ASAuthorizationControllerDelegate
-
验证
-
已经Sign In with Apple登陆过app的用户,处理
-
监听授权状态改变
4、实现
使用ASAuthorizationAppleIDButton创建button,布局,添加点击事件;
- (void)createView {
if (@available(iOS 13.0, *)) {
ASAuthorizationAppleIDButton *appleIDButton = [[ASAuthorizationAppleIDButton alloc] init];
appleIDButton.frame = CGRectMake(50, 100+CGRectGetHeight(self.view.frame) * 0.4, CGRectGetWidth(self.view.frame)-100, 50);
[appleIDButton addTarget:self action:@selector(appleIDButtonClicked) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:appleIDButton];
}
}
实现点击事件:授权请求
- (void)appleIDButtonClicked API_AVAILABLE(ios(13.0)) {
//基于用户的Apple ID授权用户,生成用户授权请求的一种机制
ASAuthorizationAppleIDProvider *provide = [[ASAuthorizationAppleIDProvider alloc] init];
//创建新的AppleID 授权请求
ASAuthorizationAppleIDRequest *request = provide.createRequest;
//在用户授权期间请求的联系信息
request.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];
//由ASAuthorizationAppleIDProvider创建的授权请求 管理授权请求的控制器
ASAuthorizationController *controller = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[request]];
//设置授权控制器通知授权请求的成功与失败的代理
controller.delegate = self;
//设置提供 展示上下文的代理,在这个上下文中 系统可以展示授权界面给用户
controller.presentationContextProvider = self;
//在控制器初始化期间启动授权流
[controller performRequests];
}
授权代理实现(授权成功,授权失败)ASAuthorizationControllerDelegate
验证
#pragma mark - ASAuthorizationControllerDelegate
//授权成功的回调
/**
当授权成功后,我们可以通过这个拿到用户的 userID、email、fullName、authorizationCode、identityToken 以及 realUserStatus 等信息。
*/
-(void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0)) {
if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
// 用户登录使用ASAuthorizationAppleIDCredential
ASAuthorizationAppleIDCredential *credential = authorization.credential;
//苹果用户唯一标识符,该值在同一个开发者账号下的所有 App 下是一样的,开发者可以用该唯一标识符与自己后台系统的账号体系绑定起来。
NSString *userId = credential.user;
NSString *state = credential.state;
NSPersonNameComponents *fullName = credential.fullName;
//苹果用户信息,邮箱
NSString *email = credential.email;
NSString *authorizationCode = [[NSString alloc] initWithData:credential.authorizationCode encoding:NSUTF8StringEncoding]; // refresh token
/**
验证数据,用于传给开发者后台服务器,然后开发者服务器再向苹果的身份验证服务端验证本次授权登录请求数据的有效性和真实性,详见 Sign In with Apple REST API。如果验证成功,可以根据 userIdentifier 判断账号是否已存在,若存在,则返回自己账号系统的登录态,若不存在,则创建一个新的账号,并返回对应的登录态给 App。
*/
NSString *identityToken = [[NSString alloc] initWithData:credential.identityToken encoding:NSUTF8StringEncoding];
/**
用于判断当前登录的苹果账号是否是一个真实用户
取值有:unsupported、unknown、likelyReal。
*/
ASUserDetectionStatus realUserStatus = credential.realUserStatus;
// 存储userId到keychain中,代码省略
······
} else if ([authorization.credential isKindOfClass:[ASPasswordCredential class]]) {
// 用户登录使用现有的密码凭证
ASPasswordCredential *passwordCredential = authorization.credential;
// 密码凭证对象的用户标识 用户的唯一标识
NSString *user = passwordCredential.user;
// 密码凭证对象的密码
NSString *password = passwordCredential.password;
_appleIDInfoTextView.text = [NSString stringWithFormat:@"%@",passwordCredential];
} else {
}
}
//失败的回调
-(void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error API_AVAILABLE(ios(13.0)) {
}
#pragma mark - ASAuthorizationControllerPresentationContextProviding
//告诉代理应该在哪个window 展示授权界面给用户
-(ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller API_AVAILABLE(ios(13.0)) {
return self.view.window;
}
已经Sign In with Apple登陆过app的用户
1、如果设备中存在iCloud Keychain凭证或者AppleID凭证,提示用户直接使用TouchID或FaceID登录即可。
2、新增ASAuthorizationPasswordRequest,如果 KeyChain 里面有登录信息的话,可以直接使用里面保存的用户名和密码进行登录。
- (void)perfomExistingAccountSetupFlows {
if (@available(iOS 13.0, *)) {
// 授权请求依赖于用于的AppleID
ASAuthorizationAppleIDRequest *authAppleIDRequest = [[ASAuthorizationAppleIDProvider new] createRequest];
// 为了执行钥匙串凭证分享生成请求的一种机制
ASAuthorizationPasswordRequest *passwordRequest = [[ASAuthorizationPasswordProvider new] createRequest];
NSMutableArray *mArr = [NSMutableArray arrayWithCapacity:2];
if (authAppleIDRequest) {
[mArr addObject:authAppleIDRequest];
}
if (passwordRequest) {
[mArr addObject:passwordRequest];
}
// ASAuthorizationRequest:对于不同种类授权请求的基类
NSArray *requests = [mArr copy];
// 由ASAuthorizationAppleIDProvider创建的授权请求 管理授权请求的控制器
ASAuthorizationController *authorizationController = [[ASAuthorizationController alloc] initWithAuthorizationRequests:requests];
// 设置授权控制器通知授权请求的成功与失败的代理
authorizationController.delegate = self;
// 设置提供 展示上下文的代理,在这个上下文中 系统可以展示授权界面给用户
authorizationController.presentationContextProvider = self;
// 在控制器初始化期间启动授权流
[authorizationController performRequests];
}
}
在 App 使用过程中,通过通知方法来监听 revoked 状态
- (void)observeAppleSignInState {
if (@available(iOS 13.0, *)) {
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(handleSignInWithAppleStateChanged:) name:ASAuthorizationAppleIDProviderCredentialRevokedNotification object:nil];
}
}
// 观察SignInWithApple状态改变
- (void)handleSignInWithAppleStateChanged:(id)noti {
}
程序启动时,监听授权状态
用户终止 App 中使用 Sign in with Apple 功能;
用户在设置里注销了 AppleId时
App 需要获取到这些状态,然后做退出登录操作,或者重新登录。
我们需要在 App 启动的时候,通过 getCredentialState:completion: 来获取当前用户的授权状态。
- (void)observeAuthticationState {
// 基于用户的Apple ID 生成授权用户请求的机制
ASAuthorizationAppleIDProvider *appleIDProvider = [ASAuthorizationAppleIDProvider new];
// 注意 存储用户标识信息需要使用钥匙串来存储 这里使用NSUserDefaults 做的简单示例
NSString *userIdentifier = [[NSUserDefaults standardUserDefaults] valueForKey:@"ShareCurrentIdentifier"];
if (userIdentifier) {
// 在回调中返回用户的授权状态
[appleIDProvider getCredentialStateForUserID:userIdentifier completion:^(ASAuthorizationAppleIDProviderCredentialState credentialState, NSError * _Nullable error) {
// 苹果证书的授权状态
switch (credentialState) {
case ASAuthorizationAppleIDProviderCredentialRevoked:
// 苹果授权凭证失效
dispatch_async(dispatch_get_main_queue(), ^{
//做对应处理
});
break;
case ASAuthorizationAppleIDProviderCredentialAuthorized:
// 苹果授权凭证状态良好
dispatch_async(dispatch_get_main_queue(), ^{
//做对应处理
});
break;
case ASAuthorizationAppleIDProviderCredentialNotFound:
// 未发现苹果授权凭证
// 可以引导用户重新登录
dispatch_async(dispatch_get_main_queue(), ^{
//做对应处理
});
break;
default:
break;
}
}];
}
}
官网swift版demo和改编的OC版
参考文章:
Sign In With Apple(一)
Sign In with Apple - 使用苹果账号登录你的应用
iOS 13 适配
Sign in with Apple
iOS 13-Sign In with Apple