本文介绍在iOS上集成Google和Apple三方登录的开发指南。

Google登录

  1. 创建项目
    1. 打开Google后台,单击左上角My Project,再在弹出框中单击创建项目

      创建项目
    2. 接下来申请配置项目参数,在集成开发界面中单击Create an OAuth clientID按钮。配置项目参数
    3. 选择刚才创建的项目,选择平台iOS,输入项目BundleID,成功之后会提示下载一个plist文件,里面包含了配置参数。plist
  2. Xcode工程配置

    在xcode工程的info.plist文件中配置url schemeURL Schemes参数填Google生成plist文件中的REVERSED_CLIENT_ID

    xcode

代码示例

#import <ALBBOpenAccountSSO/ALBBOpenAccountSSOService.h>
#import <ALBBOpenAccountCloud/ALBBOpenAccountSDK.h>

//Google生成plist文件中的CLIENT_ID
static NSString * const IMSAuthPlatformGoogleAppKey = @"xxxx.apps.googleusercontent.com";

@implementation GoogleLoginDemo

- (instancetype)init {
    self = [super init];
    if (self) {
          //登录成功通知
        [IMSNotification addObserverForName:ALBBOpenAccountNotificationUserLoggedIn object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
                if (note.object != nil && ([note.object isEqualToString:ALBBOpenAccountNotificationTrigerByREG] || [note.object isEqualToString:ALBBOpenAccountNotificationTrigerByLogin])) {

                }
            }];
    }
    return self;
}

//拉起Google授权登录
- (void)thirdAuthorizationLogin {
    id<ALBBOpenAccountSSOService> ssoService = ALBBService(ALBBOpenAccountSSOService);
    //初始化
    [ssoService setPlatform:OAAuthPlatformType_Google
                     appKey:IMSAuthPlatformGoogleAppKey
                  appSecret:nil
                redirectURL:nil];
    //三方账号授权登录
    [ssoService oauthWithPlatForm:OAAuthPlatformType_Google
                     presentingVC:self
                         delegate:self];
}

#pragma mark - SSODelegate

- (void)openAccountOAuthError:(NSError *)error Session:(ALBBOpenAccountSession *)session {
    if (error && error.code != -5) {
        //处理授权登录错误
    }
}

@end
在AppDelegate里需要处理系统回调,代码示例如下所示
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {

        NSString *sourceApplication = [options objectForKey:UIApplicationOpenURLOptionsSourceApplicationKey];
        id annotation = [options objectForKey:UIApplicationOpenURLOptionsAnnotationKey];
        return [ALBBService(ALBBOpenAccountSSOService) handleOpenUrl:url application:app
                                                   sourceApplication:sourceApplication annotation:annotation];

}

Apple登录

项目配置

  • 在苹果开发者网站,开通sign in with Apple。开通Sign in
  • 在Xcode中添加sign in with Apple。

    选中target,在Signing & Capabilities中点击Capability选择sign in with Apple。

    CapabilitySign in with Apple

代码示例

#import <ALBBOpenAccountSSO/ALBBOpenAccountSSOService.h>
#import <ALBBOpenAccountCloud/ALBBOpenAccountSDK.h>
#import <IMSApiClient/IMSConfiguration.h>
#if __has_include(<AuthenticationServices/AuthenticationServices.h>)
#import "AuthenticationServices/AuthenticationServices.h"
#endif

@implementation AppleLoginDemo

- (instancetype)init {
    self = [super init];
    if (self) {
          //登录成功通知
        [IMSNotification addObserverForName:ALBBOpenAccountNotificationUserLoggedIn object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
            if (note.object != nil && ([note.object isEqualToString:ALBBOpenAccountNotificationTrigerByREG] || [note.object isEqualToString:ALBBOpenAccountNotificationTrigerByLogin])) {

            }
        }];
    }
    return self;
}

//拉起Apple授权登录
- (void)handleAplleAuthrization {
    if (@available(iOS 13.0, *)) {
        // A mechanism for generating requests to authenticate users based on their Apple ID.
        // 基于用户的Apple ID授权用户,生成用户授权请求的一种机制
        ASAuthorizationAppleIDProvider *appleIDProvider = [ASAuthorizationAppleIDProvider new];
        // Creates a new Apple ID authorization request.
        // 创建新的AppleID 授权请求
        ASAuthorizationAppleIDRequest *request = appleIDProvider.createRequest;
        // The contact information to be requested from the user during authentication.
        // 在用户授权期间请求的联系信息
        request.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];

        // A controller that manages authorization requests created by a provider.
        // 由ASAuthorizationAppleIDProvider创建的授权请求 管理授权请求的控制器
        ASAuthorizationController *controller = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[request]];
        // A delegate that the authorization controller informs about the success or failure of an authorization attempt.
        // 设置授权控制器通知授权请求的成功与失败的代理
        controller.delegate = self;
        // A delegate that provides a display context in which the system can present an authorization interface to the user.
        // 设置提供 展示上下文的代理,在这个上下文中 系统可以展示授权界面给用户
        controller.presentationContextProvider = self;
        // starts the authorization flows named during controller initialization.
        // 在控制器初始化期间启动授权流
        [controller performRequests];
    }
}

#pragma mark - ASAuthorizationControllerDelegate

#if __has_include(<AuthenticationServices/AuthenticationServices.h>)
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization  API_AVAILABLE(ios(13.0)){
    NSMutableString *mStr = [NSMutableString string];

    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;

        NSMutableString* nick = [[NSMutableString alloc]initWithCapacity:3];
        if (givenName != nil) {
            [nick appendString:givenName];
            [nick appendString:@" "];
        }
        if (familyName != nil) {
            [nick appendString:familyName];
        }

        NSDictionary* userInfo = @{@"nick":nick.length > 0? nick : user, @"email":@""};
        NSString* identityToken = [[NSString alloc] initWithData:appleIDCredential.identityToken encoding:NSUTF8StringEncoding];

        id<ALBBOpenAccountSSOService> ssoService = ALBBService(ALBBOpenAccountSSOService);
        //苹果账号登录
        [ssoService signInWithApple:self
                           clientId:[[NSBundle mainBundle] bundleIdentifier]
                      identityToken:identityToken
                             appKey:[IMSConfiguration sharedInstance].appKey
                             openId:user
                           userInfo:userInfo
                           delegate:self];

    } else if ([authorization.credential isKindOfClass:[ASPasswordCredential class]]) {
        // 用户登录使用现有的密码凭证
        ASPasswordCredential *passwordCredential = authorization.credential;
        // 密码凭证对象的用户标识 用户的唯一标识
        NSString *user = passwordCredential.user;
        // 密码凭证对象的密码
        NSString *password = passwordCredential.password;
        [mStr appendString:user?:@""];
        [mStr appendString:password?:@""];
        [mStr appendString:@"\n"];
        NSLog(@"mStr:%@", mStr);
    } else {
        NSLog(@"授权信息均不符");
        mStr = [@"授权信息均不符" mutableCopy];
    }
}

- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error  API_AVAILABLE(ios(13.0)){

    NSLog(@"%s", __FUNCTION__);
    NSLog(@"错误信息:%@", 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;
    }

    if (errorMsg) {
        return;
    }

    NSLog(@"controller requests:%@", controller.authorizationRequests);
}

#pragma mark - ASAuthorizationControllerPresentationContextProviding

- (ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller  API_AVAILABLE(ios(13.0)){

    NSLog(@"调用展示window方法:%s", __FUNCTION__);
    // 返回window
    return self.view.window;
}
#endif

#pragma mark - SSODelegate

- (void)openAccountOAuthError:(NSError *)error Session:(ALBBOpenAccountSession *)session {
    if (error && error.code != -5) {
        //处理授权登录错误
    }
}

@end
在AppDelegate里需要处理系统回调,代码示例如下所示
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {

        NSString *sourceApplication = [options objectForKey:UIApplicationOpenURLOptionsSourceApplicationKey];
        id annotation = [options objectForKey:UIApplicationOpenURLOptionsAnnotationKey];
        return [ALBBService(ALBBOpenAccountSSOService) handleOpenUrl:url application:app
                                                   sourceApplication:sourceApplication annotation:annotation];

}