iOS Sign in with Apple 蘋果登錄帶配置步驟代碼封裝

  • 蘋果授權登錄配置

1.Identifiers 勾選 Sign In with Apple

2.配置key

3.

4.key 與 Certificates 關聯

5

6. 更新Profiles的開發配置文件並下載

7. Xcode 開啓 Sign In with Apple

  • 蘋果授權登錄代碼封裝
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, AppleLoginType) {
    AppleLoginTypeUnknown = 0,
    AppleLoginTypeSuccessful,
    AppleLoginTypeUserSuccessful,
    AppleLoginTypeFailure
};

@interface AppleLogin : UIView

///  Apple登錄
/// @param user 選填,已存user可以直接快速驗證,沒有傳nil ,斷網可驗證。
/// @param view <#view description#>
/// @param rect <#rect description#>
/// @param block <#block description#>
+(instancetype)appLogoinFromUser:(NSString *)user view:(UIView *)view rect:(CGRect)rect block:(void(^)(NSInteger state,NSString *msg,id data))block;

@end

NS_ASSUME_NONNULL_END

 

#import "AppleLogin.h"
#import <AuthenticationServices/AuthenticationServices.h>


typedef void(^AppleLoginBlock)(NSInteger state,NSString *msg,id data);
@interface AppleLogin ()
<
ASAuthorizationControllerDelegate
,ASAuthorizationControllerPresentationContextProviding
>
@property(nonatomic,strong)NSString *userId;
@property(nonatomic,strong)UIView *view;
@property(nonatomic)CGRect rect;
@property(nonatomic,copy)AppleLoginBlock appleLoginBlock;
@end

@implementation AppleLogin

+(instancetype)appLogoinFromView:(UIView *)superView rect:(CGRect)rect block:(void(^)(NSInteger state,NSString *msg,id data))block
{
    AppleLogin * appleLogin = [self appLogoinFromView:superView rect:rect];
    appleLogin.appleLoginBlock = block;
    return appleLogin;
}

+(instancetype)appLogoinFromUser:(NSString *)user view:(UIView *)view rect:(CGRect)rect block:(void(^)(NSInteger state,NSString *msg,id data))block
{
    AppleLogin * appleLogin = [self appLogoinFromView:view rect:rect];
    appleLogin.userId       = user;
    appleLogin.appleLoginBlock = block;
    return appleLogin;
}

+(instancetype)appLogoinFromView:(UIView *)superView rect:(CGRect)rect
{
    AppleLogin * appleLogin = [[AppleLogin alloc]initWithFrame:rect];
    appleLogin.view         = superView;
    appleLogin.rect         = rect;
    [appleLogin initUI];
    return appleLogin;
}

- (void)initUI
{
    if (@available(iOS 13.0, *))
    {
        ASAuthorizationAppleIDButton *button = [ASAuthorizationAppleIDButton buttonWithType:ASAuthorizationAppleIDButtonTypeSignIn style:ASAuthorizationAppleIDButtonStyleBlack];
        button.frame = CGRectMake(0, 0, self.rect.size.width, self.rect.size.height);
        button.layer.masksToBounds = YES;
        button.layer.cornerRadius = self.frame.size.width/2;
        [button addTarget:self action:@selector(signInWithApple) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:button];
        [self.view addSubview:self];
    }
}

#pragma mark ————————————— 登錄按鈕點擊事件 —————————————
- (void)signInWithApple API_AVAILABLE(ios(13.0))
{
    if (@available(iOS 13.0, *))
    {
         NSLog(@"Apple Login Click");
        //基於用戶的Apple ID授權用戶,生成用戶授權請求的一種機制
        ASAuthorizationAppleIDProvider *appleIDProvider = [ASAuthorizationAppleIDProvider new];
        if (_userId.length == 0)
        {
            NSLog(@"授權請求AppleID");
            ASAuthorizationAppleIDRequest *request = appleIDProvider.createRequest;
            [request setRequestedScopes:@[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail]];
            //由ASAuthorizationAppleIDProvider創建的授權請求 管理授權請求的控制器
            ASAuthorizationController *controller = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[request]];
            //設置授權控制器通知授權請求的成功與失敗的代理
            controller.delegate = self;
            //設置提供 展示上下文的代理,在這個上下文中 系統可以展示授權界面給用戶
            controller.presentationContextProvider = self;
            //在控制器初始化期間啓動授權流
            [controller performRequests];
        }
        else
        {
//            NSLog(@"快速登錄使用授權登錄返回的 user ");
            //快速登錄
            [appleIDProvider getCredentialStateForUserID:_userId completion:^(ASAuthorizationAppleIDProviderCredentialState credentialState, NSError * _Nullable error) {

                if (credentialState == ASAuthorizationAppleIDProviderCredentialAuthorized)
                {
                    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
                    if (self.appleLoginBlock)
                    {
                      self.appleLoginBlock(AppleLoginTypeUserSuccessful,@"ok",dic);
                    }
                }
                else
                {   NSMutableDictionary *dic = [NSMutableDictionary dictionary];
                    [dic setValue:error.description forKey:@"errorMsg"];
                    [dic setValue:[NSNumber numberWithInteger:error.code] forKey:@"code"];
                    if (self.appleLoginBlock)
                    {
                      self.appleLoginBlock(AppleLoginTypeFailure,error.description,dic);
                    }
                }
            }];
        }
    }
    else
    {

    }
}

#pragma mark ————————————— 成功回調 —————————————
- (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 *nickname = appleIDCredential.fullName.nickname;
            NSString *email = appleIDCredential.email;
            NSString *state = appleIDCredential.state;
            NSData *identityToken = appleIDCredential.identityToken;
            NSData *authorizationCode = appleIDCredential.authorizationCode;
            ASUserDetectionStatus realUserStatus = appleIDCredential.realUserStatus;
            
            // 服務器驗證需要使用的參數
            NSString *identityTokenStr = [[NSString alloc] initWithData:identityToken encoding:NSUTF8StringEncoding];
            NSString *authorizationCodeStr = [[NSString alloc] initWithData:authorizationCode encoding:NSUTF8StringEncoding];
            //  NSLog(@"%@\n\n%@", identityTokenStr, authorizationCodeStr);

            NSMutableDictionary *dic = [NSMutableDictionary dictionary];
            [dic setValue:state forKey:@"state"];
            [dic setValue:user forKey:@"user"];
            [dic setValue:email forKey:@"email"];
            [dic setValue:familyName forKey:@"familyName"];
            [dic setValue:givenName forKey:@"givenName"];
            [dic setValue:nickname forKey:@"nickname"];
//            [dic setValue:appleIDCredential forKey:@"appleIDCredential"];
            [dic setValue:authorizationCodeStr forKey:@"authorizationCode"];
            [dic setValue:identityTokenStr forKey:@"identityToken"];
//            [dic setValue:@(realUserStatus) forKey:@"realUserStatus"];
            
            if (self.appleLoginBlock)
            {
                self.appleLoginBlock(AppleLoginTypeSuccessful, @"ok",dic);
            }
            //  需要使用鑰匙串的方式保存用戶的唯一信息 Keychain
        }
        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;
            NSMutableDictionary *dic = [NSMutableDictionary dictionary];
            [dic setValue:user forKey:@"user"];
            [dic setValue:password forKey:@"password"];
            if (self.appleLoginBlock)
            {
                self.appleLoginBlock(AppleLoginTypeSuccessful, @"ok",dic);
            }
        }
        else
        {
//            NSLog(@"授權信息均不符");
            NSString *errorMsg = @"授權信息不符";
            NSMutableDictionary *dic = [NSMutableDictionary dictionary];
            [dic setValue:errorMsg forKey:@"errorMsg"];
            if (self.appleLoginBlock)
            {
              self.appleLoginBlock(AppleLoginTypeFailure,errorMsg,dic);
            }
        }
}

#pragma mark ————————————— 失敗回調 —————————————
- (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;
    }
    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    [dic setValue:errorMsg forKey:@"errorMsg"];
    [dic setValue:[NSNumber numberWithInteger:error.code] forKey:@"code"];
    if (self.appleLoginBlock)
    {
      self.appleLoginBlock(AppleLoginTypeFailure,errorMsg,dic);
    }
}

#pragma mark ————————————— 告訴代理應該在哪個window 展示內容給用戶 —————————————
- (ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller API_AVAILABLE(ios(13.0))
{
    return [UIApplication sharedApplication].windows.lastObject;
}

@end
  • 調用
#import "ViewController.h"
#import "AppleLogin.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    // user在第一次蘋果驗證時傳空,如果對user做了存儲,傳user可以快速驗證(簡單說就是你驗證過的user手機裏會存,並且每次返回的user都是不一樣的,user正確斷網也可以驗證)
    NSString *user ;
    [AppleLogin appLogoinFromUser:user view:self.view rect:CGRectMake(100, 100, 60, 60) block:^(NSInteger state, NSString * _Nonnull msg, id  _Nonnull data) {
        if (state == AppleLoginTypeSuccessful)
        {
             NSLog(@"授權成功 %@",data);
        }
        else if (state == AppleLoginTypeUserSuccessful)
        {
              NSLog(@"賬號驗證成功");
        }
        else
        {
           NSLog(@"驗證失敗: %@",msg);
        }
        
    }];
}


@end

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章