一、功能提出
2019年6月3日,apple提出开发者们可以集成sign in with apple功能,其为跨平台的,iOS、macOS、watchOS、tvOS、JS均可使用,以下主要针对iOS平台。2019年9月12日,apple更新App Store Review Guidelines,提出“Starting today, new apps submitted to the App Storemust follow these guidelines. Existing apps and app updates must follow them by April 2020.”。最新的要求如下:(https://developer.apple.com/app-store/review/guidelines/#third-party-software)
依据上述描述,在4月底前上线的万视达版本必须适配sign in with apple。
二、开发sign in with apple注意事项
需要在apple后台打开该选项,并且重新生成Profiles配置文件,并安装到xcode中。如图所示:
服务端验证需要的文件,一个是私钥文件,一个是config.json文件
创建用于客户端省份验证的私钥,如下图:
点击右侧configure,选择之前创建的Primary App ID,保存之后,Apple会生成一个新的私钥,只能下载一次,目前已创建,私钥已保存。下载文件格式为p8,已转为.txt格式,方便后续查看。
config.json文件格式如下:(目前创建的私钥等文件均未被使用,因服务器选择校验的方式不同)
在xcode中的准备工作:
在Xcode11 Signing & Capabilities中添加Sign In With Apple
在项目中的Build Phases中添加AuthenticationServices.framework.
三、实现
目前项目中QQ、微信三方登录使用的是ShareSDK,其最新版本也提供了apple登录,所以客户端集成sign in with apple使用ShareSDK提供的接口。注意仅支持iOS13及以上。
接口:返回apple账号信息
[ShareSDK authorize:SSDKPlatformTypeAppleAccount settings:nil onStateChanged:^(SSDKResponseState state, SSDKUser *user, NSError *error) {
if (state == SSDKResponseStateSuccess)
{
NSLog(@"rawData---%@",user.rawData);
NSLog(@"credential--%@",[user.credential rawData]);
}
else
{
NSLog(@"%@",error.userInfo);
}
}];
此接口第一次登录返回内容示例:(注意:email可选是否匿名,名称可以编辑,也可以不填写)
退出登录:在"设置->账户->密码与安全性->使⽤您的apple ID 的 App"中停止使用apple id,下次登录则同上方第一次登录。
接口:登录状态监听
[AppleAccountConnector addObserve:nil isFirstAddCallBack:YES forAppleAccountLoginStateHandler:^(SSDKAppleAccountState state, SSDKUser * _Nonnull user, NSError * _Nonnull error) {
if (state != SSDKAppleAccountStateAuthorized) {
}else{
if (user) {
NSLog(@"------%@", user.rawData);
}
}
}];
四、Apple提供自带的API实现,仅支持iOS13及以上
可以使用ASAuthorizationAppleIDButton选取适用的控件
按钮授权实现:
// 处理授权
- (void)handleAuthorizationAppleIDButtonPress{
NSLog(@"////////");
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登录");
}
}
如果存在iCloud Keychain 凭证或者AppleID 凭证提示用(如爱奇艺登录)
- (void)perfomExistingAccountSetupFlows{
NSLog(@"///已经认证过了/////");
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登录");
}
}
授权回调如下:
//@optional 授权成功地回调
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0)){
NSLog(@"授权完成:::%@", authorization.credential);
NSLog(@"%s", FUNCTION);
NSLog(@"%@", controller);
NSLog(@"%@", authorization);
if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
// 用户登录使用ASAuthorizationAppleIDCredential
ASAuthorizationAppleIDCredential *appleIDCredential = authorization.credential;
NSString *user = appleIDCredential.user;
// 使用过授权的,可能获取不到以下三个参数
NSString *familyName = appleIDCredential.fullName.familyName;
NSString *givenName = appleIDCredential.fullName.givenName;
NSString *email = appleIDCredential.email;
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);
// Create an account in your system.
// 需要使用钥匙串的方式保存用户的唯一信息
// [YostarKeychain save:KEYCHAIN_IDENTIFIER(@"userIdentifier") data:user];
}else if ([authorization.credential isKindOfClass:[ASPasswordCredential class]]){
// 这个获取的是iCloud记录的账号密码,需要输入框支持iOS 12 记录账号密码的新特性,如果不支持,可以忽略
// Sign in using an existing iCloud Keychain credential.
// 用户登录使用现有的密码凭证
ASPasswordCredential *passwordCredential = authorization.credential;
// 密码凭证对象的用户标识 用户的唯一标识
NSString *user = passwordCredential.user;
// 密码凭证对象的密码
NSString *password = passwordCredential.password;
}else{
NSLog(@"授权信息均不符");
}
}
// 授权失败的回调
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error API_AVAILABLE(ios(13.0)){
// Handle error.
NSLog(@"Handle error:%@", error);
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:
break;
}
NSLog(@"%@", errorMsg);
}
苹果提供了登录按钮ASAuthorizationAppleIDButton (继承自UIControl)。
这个按钮具有两种文案类型和三个样式,分别是:
a@available(iOS 13.0, *)public enum ButtonType : Int {
case signIn
case continue
public static var default
: ASAuthorizationAppleIDButton.ButtonType { get }
}
@available(iOS 13.0, *)public enum Style : Int {
case white
case whiteOutline
case black
}
·Apple 提供的登录按钮有三种外观:白色,带有黑色轮廓线的白色和黑色。
·文案有两种:Sign In with Apple 和 Continue with Apple。(具体使用哪个文案,根据自身业务需求来定)
按钮宽高默认值为 {width:130, height:30}。
比如背景色不能更改,文案只有两种可选,并且值不能修改,可以调整的只有圆角cornerRadius和size 。
按钮显示的文字都是英文的,不可以直接修改,不过可以添加本地化即可。
PS:
服务端验证参考资料
https://blog.csdn.net/wpf199402076118/article/details/99677412
官方资料
https://developer.apple.com/documentation/signinwithapplerestapi
https://www.jianshu.com/p/26383db8bf10