本人在昨天下班之前提交了一个ipa,然后今天早上7点收到苹果的二进制被拒邮件:
Guideline 4.8 - Design - Sign in with Apple
We noticed that your app uses a third-party login service but does not offer Sign in with Apple.
Next Steps
To resolve this issue, please revise your app to offer Sign in with Apple as an equivalent login option.
Resources
To learn more, see the Sign in with Apple Overview.
Please see attached screenshot for details.
由于最近一段时间忙于多款app版本修改上线,并未关注苹果官网最新动态,并且前几款app并未用到第三方登录,所以未发现第三方登录政策变更为强制执行了!~
好吧既然发现问题,那么久来解决问题吧~
首先我们得加上苹果第三方登录权限:
然后去苹果开发者中心 Identifiers 设置一下Identifiers权限
到这一步久说明前期的权限工作告一段落了,这个时候我们就得添加AuthenticationServices.framework
了,因为苹果的文档有说明AuthenticationServices是来提供Apple登录服务的:
终于可以正式进行第三方登录开发了
你可以选择添加一个苹果自带按钮:
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(signInWithApple) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:appleIDButton];
}
也可以跟我一样自定一个按钮
然后就是苹果登录代码授权唤起了:
- (void)signInWithApple API_AVAILABLE(ios(13.0)){
ASAuthorizationAppleIDProvider *appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init];
// 通过 provider 创建一个 request
ASAuthorizationAppleIDRequest *appleIDRequest = [appleIDProvider createRequest];
// 要获取的内容
appleIDRequest.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];
// 系统提供的 Controller,必须使用,需要传入 requests 数组
ASAuthorizationController *authController = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[appleIDRequest/*, passwordRequest*/]];
// 设置代理,接收登录成功/失败的回调
authController.delegate = self;
// 页面跳转相关的,通过一个代理方法传入一个 window
authController.presentationContextProvider = self;
[authController performRequests];
}
这里要说一下ASAuthorizationController
的delegate
和presentationContextProvider
AS_EXTERN API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0))
@protocol ASAuthorizationControllerDelegate <NSObject>
@optional
//成功回调
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization NS_SWIFT_NAME(authorizationController(controller:didCompleteWithAuthorization:));
/*失败回调
ASAuthorizationErrorCanceled : 用户取消了授权
ASAuthorizationErrorFailed : 授权失败
ASAuthorizationErrorInvalidResponse :授权响应无效
ASAuthorizationErrorNotHandled : 未能处理授权
ASAuthorizationErrorUnknown : 授权失败未知原因
*/
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error NS_SWIFT_NAME(authorizationController(controller:didCompleteWithError:));
@end
AS_EXTERN API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0)) API_UNAVAILABLE(watchos)
@protocol ASAuthorizationControllerPresentationContextProviding <NSObject>
@required
#if !TARGET_OS_WATCH
/*! @abstract Return a view anchor that is most appropriate for athorization UI to be presented over. This view will be used as a hint if a credential provider requires user interaction.
*/
//返回一个控制窗口~ 一般用keywindow
- (ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller;
#endif
@end
最后附加上我自己的代码:
- (void)signInWithApple API_AVAILABLE(ios(13.0)){
ASAuthorizationAppleIDProvider *appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init];
// 通过 provider 创建一个 request
ASAuthorizationAppleIDRequest *appleIDRequest = [appleIDProvider createRequest];
// 要获取的内容
appleIDRequest.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];
// 系统提供的 Controller,必须使用,需要传入 requests 数组
ASAuthorizationController *authController = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[appleIDRequest/*, passwordRequest*/]];
// 设置代理,接收登录成功/失败的回调
authController.delegate = self;
// 页面跳转相关的,通过一个代理方法传入一个 window
authController.presentationContextProvider = self;
[authController performRequests];
}
#pragma mark ------ ASAuthorizationControllerDelegate ------
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error API_AVAILABLE(ios(13.0)){
// 登录失败
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;
default:
errorMsg= @"授权请求失败未知原因";
break;
}
[MBProgressHUD showInfoMessage:errorMsg];
}
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0)){
// 登录成功
ZMdebugLog(@"auth success!, %@", authorization.credential);
if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
ASAuthorizationAppleIDCredential *credential = (ASAuthorizationAppleIDCredential *)authorization.credential;
// ZMdebugLog(@"user:%@ , email:%@ , fullName:%@ , identityToken:%@ , state:%@ , authorizationCode:%@ ",credential.user,credential.email,credential.fullName,credential.identityToken.string,credential.state,credential.authorizationCode);
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
[dic setValue:_zms(credential.user) forKey:@"accountid"];
[dic setValue:_zms(credential.fullName.nickname) forKey:@"nickname"];
[dic setValue:[NSNumber numberWithInteger:0] forKey:@"sex"];
[dic setValue:_zms(@"") forKey:@"headimgurl"];
[dic setValue:_zms(credential.identityToken.string) forKey:@"account2id"];
[dic setValue:@7 forKey:@"type"];
self.userDic = dic;
//----- 登录 ------
[self requesLoginType:7 withaccount:[dic objectForKey:@"accountid"]];
}
}
#pragma mark ------ ASAuthorizationControllerPresentationContextProviding ------
- (ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller API_AVAILABLE(ios(13.0)){
return self.view.window;
}