公司项目需要接入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{
// 处理不支持系统版本,ios13以下使用sign in with Apple web登录
NSLog(@"the os version less than 13.0,SignInWithApple web");
UIViewController *vc = [UIApplication sharedApplication].keyWindow.rootViewController;
if (vc.parentViewController) {
vc = vc.parentViewController;
}
GmSdkSignInWithAppleViewController *signInWithAppleWeb = [[GmSdkSignInWithAppleViewController alloc]init];
signInWithAppleWeb.modalPresentationStyle = UIModalPresentationFullScreen;
UINavigationController *controller = [[UINavigationController alloc]initWithRootViewController:signInWithAppleWeb];
[vc presentViewController:controller animated:YES completion:nil];
}
2.sign in Apple没有自动登录接口,如果自己项目中需要自动登录功能,可以使用登录保存的identityToken直接去服务器做登录验证,具体代码如下:
- (void)AutoSignIn:(void (^)(GMResult *, GmUser *))completionHandler{
NSLog(@"SignInWithApple AutoLogin");
NSString *identityToken = [self getIdentityToken];
if (identityToken) {
[self doLoginVerify:identityToken];
}else{
GmUser *user = [[GmUser alloc] init];
GMResult *result = [[GMResult alloc] initWithResult:NOT_AUTHENTICATED message:@"auto login fail"];
if (_completionHandler != nil) {
_completionHandler(result,user);
}
}
}
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) {
[self setUserIdentifier:user];
}
NSData *identityToken = appleIDCredential.identityToken;
// NSData *authorizationCode = appleIDCredential.authorizationCode;
// 服务器验证需要使用的参数
NSString *identityTokenStr = [[NSString alloc] initWithData:identityToken encoding:NSUTF8StringEncoding];
NSLog(@"identityToken:%@\n", identityTokenStr);
if (identityTokenStr) {
[self setIdentityToken:identityTokenStr];
[self doLoginVerify:identityTokenStr];
}
// NSString *authorizationCodeStr = [[NSString alloc] initWithData:authorizationCode encoding:NSUTF8StringEncoding];
}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;
}else{
NSLog(@"SignInWithApple授权信息均不符");
GMResult *result = [[GMResult alloc] initWithResult:SERVICE message:@"SignInWithApple授权信息均不符"];
GmUser *user = [[GmUser alloc] init];
if (_completionHandler != nil) {
_completionHandler(result,user);
}
}
}
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