公司项目需要接入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