iOS13 sign in with Apple客户端接入遇到的一些问题

晋安国
2023-12-01

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

 类似资料: