概述及资源

本文是OneLogin iOS SDK的部署文档,用于指导OneLogin iOS SDK的集成,读者需具有一定iOS编程知识基础。

环境需求

条目 资源
开发目标 iOS8+
开发环境 Xcode 11+
系统依赖 libc++.1.tbdlibz.1.2.8.tbd
SDK 三方依赖 account_login_sdk_noui_core.frameworkEAccountApiSDK.frameworkTYRZSDK.frameworkTYRZResource.bundle
包增量 1.9.0之前版本为798K(0.78M),1.9.0版本为985K(0.96M)
网络制式 移动2G/3G/4G,联通3G/4G,电信4G(2G/3G网络下时延相对较高,成功率相对较低)
网络环境 打开蜂窝数据流量并且给予应用蜂窝数据权限

相关开发资料

条目 资源
产品结构流程 交互流程, 通讯流程
接口文档 OneLogin iOS API Ref 或查看头文件注释
错误码 Error Code 列表

接入流程

注册账号

访问极验管理后台,按照步骤注册极验账号,若已注册可直接登录。进入【身份认证】模块,若无此模块权限,可联系您的专属极验商务开通权限。

创建应用

在极验管理后台【OneLogin–设置】中,提交您的APP信息生成一组APPID和APPKEY,iOS、Android APP支持共用一组APPID和APPKEY。

由于一键登录过程会对APP包名等信息进行校验,因此每新增一个应用或修改原有信息均需在管理后台重新提交审核。集成时需注意检查APPID和包名/包签名的一致性,不一致情况SDK会返回错误码。

快速体验Demo

iOS压缩包附带的OneLoginExample文件夹中是极验的示例工程,使用Xcode打开示例工程,修改bundleID和AppId,直接运行起来即可进行快速体验测试。

业务逻辑流程

流程概述

极验OneLogin iOS SDK主要业务逻辑如下:

1、预取号

a)获取脱敏手机号,为拉起授权页做准备。预取号成功之后方可拉起授权页。

b)建议在执行拉起授权页面方法前,提前一段时间调用预取号方法以获得最佳用户体验(预取号需要1-3s时间),比如放在应用启动或进入登录页的前一个页面时调用。另外用户登出时也是调用该方法的时机。

c)预取号有效期电信/移动1小时,联通10分钟。

d)建议先判断用户登录状态再决定是否调用预取号方法,已登录状态用户无需调用该方法。

2、拉起授权页面

a)预取号成功之后方可调用该方法拉起授权页面,调用该方法前建议先通过+ (BOOL)isPreGettedTokenValidate;方法判断预取号成功状态。

接口调用逻辑

极验OneLogin iOS SDK提供两种接口调用方式实现一键登录:

1、预取号和授权页拉起时机均由开发者自主控制。使用此调用逻辑,开发者需自主处理预取号的时机和超期重试的逻辑等。使用这种方式时,请使用OneLogin类中的方法,具体调用步骤如下:

a)+ (void)registerWithAppID:(NSString *)appID;注册AppId

b)+ (void)preGetTokenWithCompletion:(void(^)(NSDictionary *sender))completion; 预取号(应用启动或进入登录页的前一个页面、用户登出时是调用该方法的时机,预取号超期等逻辑需开发者自主处理)

c)+ (void)requestTokenWithViewController:(nullable UIViewController *)viewController viewModel:(nullable OLAuthViewModel *)viewModel completion:(void(^)(NSDictionary * _Nullable result))completion; 拉起授权页面(调用该方法前建议先判断预取号是否成功)

2、预取号逻辑封装在SDK内部,开发者只需控制授权页拉起时机。SDK内部处理预取号的逻辑,包括预取号超期后的重新预取号,以及弱网状态下的重试等。使用这种方式时,请使用OneLoginPro类中的方法。

a)+ (void)registerWithAppID:(NSString *)appID;注册AppId

b)+ (void)requestTokenWithViewController:(nullable UIViewController *)viewController viewModel:(nullable OLAuthViewModel *)viewModel completion:(void(^)(NSDictionary * _Nullable result))completion; 拉起授权页面

开发流程

获取 SDK 及 Demo

Tips:1.8.0(不含)以下版本升级到最新版本,终端在拿到token去服务端校验时,需多传一个参数,服务端接口必须一同调整,否则会导致电信取号失败

极验官网下载

下载获取最新版本(1.9.0)

点击下载

下载获取1.7.3版本(从该版本以下版本升级到该版本,服务端接口不需调整)

点击下载

Cocoapods获取

执行pod repo update更新

Podfile里面添加以下代码:

# 以下两种版本选择方式示例

# 集成最新版极验SDK:
pod 'GTOneLoginSDK'

# 集成指定版本极验SDK,具体版本号可先执行pod search GTOneLoginSDK,根据返回的版本信息自行决定:
pod 'GTOneLoginSDK', '~> 1.9.0'

保存并执行pod install即可,若未执行pod repo update,请执行pod install --repo-update

Demo请到Github上查看

导入 SDK 到项目工程并配置开发环境

  1. 将下载获取的OneLogin.framework, account_login_sdk_noui_core.frameworkEAccountApiSDK.frameworkTYRZSDK.framework以及在OneLoginResource.bundleTYRZResource.bundle共6个文件添加到工程中, 确保Copy items if needed已被勾选。

    此外, 需要添加libc++.1.tbdlibz.1.2.8.tbd库进行依赖。

    添加完后, 以Linked Frameworks and Libraries方式导入 framework。在拖入OneLogin.framework, account_login_sdk_noui_core.frameworkEAccountApiSDK.frameworkTYRZSDK.framework到工程后, 请检查所有的.framework是否被添加到PROJECT -> Build Phases -> Linked Frameworks and Libraries, 以确保正常编译。

    linkedlibraries

  2. 针对静态库中的Category, 需要在对应 target 的Build Settings->Other Linker Flags添加-ObjC编译选项。如果依然有问题,再添加-all_load

    linkerflags

  3. 目前运营商个别接口为http请求,对于全局禁用http的项目,需要设置http白名单。以下为运营商http接口域名和ip名单:wap.cmpassport.com、id6.me、mdn.open.wo.cn。配置ATS,在 info.plist 文件中添加 App Transport Security Settings 项,并在其中添加 Exception Domains 子项,设置如下:

    linkerflags

    可以直接打开Demo的plist文件,将对应xml文件拷贝至您自己的工程,如下:

<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>wap.cmpassport.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
</dict>
<key>id6.me</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
</dict>
<key>mdn.open.wo.cn</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
</dict>
<key>onepass.geetest.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>

配置接口

开发者集成客户端 SDK 前, 必须先在您的服务器上搭建相应的服务端获取登录信息的接口,并配置从极验后台获取的AppID。这里以服务端配置成功,客户端开发步骤为例,如下:

上文第1种接口调用方式

1. 用 AppID 注册 OneLogin
[OneLogin registerWithAppID:@"---<申请的AppID>---"];
2. 调用预取号接口

建议将预取号时机放在需要进行授权登录页面的前一两个步骤就行,比如,可以放在要点击进行授权登录页面的viewDidLoad方法中

[OneLogin preGetTokenWithCompletion:^(NSDictionary * _Nonnull result) {

}];
3. 调用取号接口

开发者在完成预取号后, 通过该接口拉起授权页面,在授权页面点击一键登录时,获取用于获取该用户手机号信息的访问令牌, 使用该访问令牌去查询用户的手机号及相关信息

if ([OneLogin isPreGettedTokenValidate]) {
[OneLogin requestTokenWithViewController:self viewModel:self.olAuthViewModel completion:^(NSDictionary * _Nullable result) {
if (result.count > 0 && result[@"status"] && 200 == [result[@"status"] integerValue]) { // 获取token成功
// TO-DO
// 校验和获取登录的用户的数据

} else {
NSLog(@"result: %@", result);
}
}];
} else {
[OneLogin preGetTokenWithCompletion:^(NSDictionary * _Nonnull result) {
NSLog(@"OneLogin preGetTokenWithCompletion result: %@", result);
if (result.count > 0 && result[@"status"] && 200 == [result[@"status"] integerValue]) {
[OneLogin requestTokenWithViewController:wself viewModel:wself.olAuthViewModel completion:^(NSDictionary * _Nullable result) {
if (result.count > 0 && result[@"status"] && 200 == [result[@"status"] integerValue]) { // 获取token成功
// TO-DO
// 校验和获取登录的用户的数据

} else {
NSLog(@"result: %@", result);
}
}];
} else { // 预取号失败

}
}];
}

上文第2种接口调用方式

1. 用 AppID 注册 OneLoginPro

建议将注册时机放在需要进行授权登录页面的前一两个步骤就行,比如,可以放在要点击进行授权登录页面的viewDidLoad方法中

[OneLoginPro registerWithAppID:@"---<申请的AppID>---"];
2. 调用取号接口

通过该接口拉起授权页面,在授权页面点击一键登录时,获取用于获取该用户手机号信息的访问令牌, 使用该访问令牌去查询用户的手机号及相关信息

[OneLoginPro requestTokenWithViewController:self viewModel:viewModel completion:^(NSDictionary * _Nullable result) {
if (result.count > 0 && result[@"status"] && 200 == [result[@"status"] integerValue]) { // 获取token成功
// TO-DO
// 校验和获取登录的用户的数据

}
else {
NSLog(@"result: %@", result);
}
}];

代码示例

在工程中的文件头部导入静态库 OneLoginSDK.framework

#import <OneLoginSDK/OneLoginSDK.h>

上文第1种接口调用方式

1. 注册

在相应的控制页初始化方法中对OneLoginSDK实例调用注册方法:

[OneLogin registerWithAppID:@"---<申请的AppID>---"];
2. 预取号
[OneLogin preGetTokenWithCompletion:^(NSDictionary * _Nonnull result) {

}];
3. 获取免密登录 token 并使用 token 获取用户登录信息

拉起授权页面, 需要设置UIViewController, 以展示授权页面, 并让用户接受使用条款

自定义部分见Demo和接口文档

- (void)requestToken {
OLAuthViewModel *viewModel = [[OLAuthViewModel alloc] init];
// TO-DO 自定义viewModel
// viewModel...

[OneLogin requestTokenWithViewController:self viewModel:viewModel completion:^(NSDictionary * _Nullable result) {
NSLog(@"token result: %@", result);
if (result.count > 0 && result[@"status"] && 200 == [result[@"status"] integerValue]) {
// TO-DO
// 获取到token, 并进行手机号查询
NSString *processID = [result objectForKey:@"processID"];
NSString *appID = [result objectForKey:@"appID"];
NSString *token = [result objectForKey:@"token"];
NSString *authcode = result[@"authcode"];
[self validateToken:token appID:appID processID:processID authcode:authcode];
} else { // 请处理获取token的错误, 更多错误码请参考错误码文档

}
}];
}

// 使用token进行校验, 并获取用户的登录信息
- (void)validateToken:(NSString *)token appID:(NSString *)appID processID:(NSString *)processID authcode:(NSString *)authcode {

// 根据用户自己接口构造
// 下面以POST, application/json 为例
NSURL *url = [NSURL URLWithString:@"---<您的校验接口地址>---"];

NSMutableURLRequest *mRequest = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:(NSURLRequestCachePolicy)0 timeoutInterval:10.0];

NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
if (token) {
params[@"token"] = token;
}
if (appID) {
params[@"id_2_sign"] = appID;
}
if (processID) {
params[@"process_id"] = processID;
}
if (authcode) {
params[@"authcode"] = authcode;
}

NSData *data = [NSJSONSerialization dataWithJSONObject:params options:(NSJSONWritingOptions)0 error:nil];

mRequest.HTTPMethod = @"POST";
mRequest.HTTPBody = data;

[[[NSURLSession sharedSession] dataTaskWithRequest:mRequest
completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// TO-DO
// 处理用户信息
NSLog(@"result data: %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}] resume];

}

上文第2种接口调用方式

1. 注册及预取号

在相应的控制页初始化方法中对OneLoginSDK实例调用注册方法:

[OneLoginPro registerWithAppID:@"---<申请的AppID>---"];
2. 获取免密登录 token 并使用 token 获取用户登录信息

拉起授权页面, 需要设置UIViewController, 以展示授权页面, 并让用户接受使用条款

自定义部分见Demo和接口文档

- (void)requestToken {
OLAuthViewModel *viewModel = [[OLAuthViewModel alloc] init];
// TO-DO 自定义viewModel
// viewModel...

[OneLoginPro requestTokenWithViewController:self viewModel:viewModel completion:^(NSDictionary * _Nullable result) {
NSLog(@"token result: %@", result);
if (result.count > 0 && result[@"status"] && 200 == [result[@"status"] integerValue]) {
// TO-DO
// 获取到token, 并进行手机号查询
NSString *processID = [result objectForKey:@"processID"];
NSString *appID = [result objectForKey:@"appID"];
NSString *token = [result objectForKey:@"token"];
NSString *authcode = result[@"authcode"];
[self validateToken:token appID:appID processID:processID authcode:authcode];
} else { // 请处理获取token的错误, 更多错误码请参考错误码文档

}
}];
}

// 使用token进行校验, 并获取用户的登录信息
- (void)validateToken:(NSString *)token appID:(NSString *)appID processID:(NSString *)processID authcode:(NSString *)authcode {

// 根据用户自己接口构造
// 下面以POST, application/json 为例
NSURL *url = [NSURL URLWithString:@"---<您的校验接口地址>---"];

NSMutableURLRequest *mRequest = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:(NSURLRequestCachePolicy)0 timeoutInterval:10.0];

NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
if (token) {
params[@"token"] = token;
}
if (appID) {
params[@"id_2_sign"] = appID;
}
if (processID) {
params[@"process_id"] = processID;
}
if (authcode) {
params[@"authcode"] = authcode;
}

NSData *data = [NSJSONSerialization dataWithJSONObject:params options:(NSJSONWritingOptions)0 error:nil];

mRequest.HTTPMethod = @"POST";
mRequest.HTTPBody = data;

[[[NSURLSession sharedSession] dataTaskWithRequest:mRequest
completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// TO-DO
// 处理用户信息
NSLog(@"result data: %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}] resume];

}

附录

1.客户端集成插件(除了原生的iOS SDK 之外,OneLogin提供主流的开发工具集成插件)

React Native:https://github.com/GeeTeam/gt-onelogin-rn-example

Flutter:https://github.com/GeeTeam/gt-onelogin-flutter-example

2.更详细示例代码见 Demo

更详细的接口说明见接口文档或 SDK 头文件

常见问题


Q 1.移动手机号报获取token失败:desc=错误的请求签名, resultCode=103101:

R: 移动运营商旧版本bug

Tips:SDK1.7.3以下版本会出现,可更新SDK或按照下面方法进行解决

S: 工程中的Info.plist中添加bundleId对应的key-value。搜索Xcode项目工程中的.strings国际化文件,如果app存在本地国际化文件,请在每个本地国际化文件中添加CFBundleIdentifier,各个语言版本文件中都需要添加


Q 2.预取号时机:

R: 预取号比较耗时,若直接预取号之后再进入授权页面,会影响用户体验

S: 建议用户提前预取号,可以放到 didFinishLaunchingWithOptions 方法中,因获取运营商信息的时候需要用到window,建议要放到设置了 window 的 rootViewController 之后


Q 3.预取号成功后,调用取号方法,取号页面无法弹起:

R:a.之前弹起过一次取号页面,只是在取号成功后没有关闭该页面,然后又调用取号方法;

b.当前流量为移动,且网络状态极差

S: (1)在授权页面,取号成功后,必须调用 SDK 的 dismissAuthViewController 方法关掉授权页面;

(2)由于移动进入授权页面时要检测网络状态,若网络极差则无法进入授权页面


Q 4.SDK报8001错误:

R: ATS白名单未设置

A: 参考官网部署文档设置ATS白名单


Q 5.支持横屏的app在双卡手机上无法获取运营商信息:

R: 获取运营商信息时需要用到状态栏信息,而只支持横屏的app中无法获取状态栏信息

A: 工程支持竖屏,在对应的 ViewController 中设置为只支持横屏


Q 6.CocoaPods 无法获取 OneLogin:

R: 若在集成极验 SDK 之前就安装了 CocoaPods,安装完成之后,会在本地有一份缓存,缓存中并没有 OneLogin

A: a.删掉缓存的索引,使用 pod setup 重新建立索引即可;

b.使用 pod install –repo-update 安装


Q 7.自定义协议点击无响应:

R: a.初始化协议时,对应的 block 没有传 nil,但是在 block 中又没做任何操作;

b.多个协议使用了相同的URL

A: (1)删掉缓存的索引,使用 pod setup 重新建立索引即可;

(2)使用 pod install –repo-update 安装


Q 8.在授权页面,当前流量卡为电信时,点击一键登录报 40399:

R: 电信 SDK 对 topClass 的校验未通过

Tips:SDK1.8.0以下版本会出现,可更新SDK或按照下面方法进行解决

A: app内部存在多个 window 的情况时,授权页面要放到keyWindow


Q 9.联通预取号报 -40201 错误:

R: 用户修改了手机时间

A: 手机调为正常时间即可;若当前时间恢复正常后依然报错,检查下当前网络环境


Q 10.iOS 13 双卡预取号失败:

R: 1.7.3 之前的版本不支持 iOS 13 双卡

A: 升级到 1.8.0 版本


Q 11.- (BOOL)application:(UIApplication)application didFinishLaunchingWithOptions:(NSDictionary)launchOptions 方法中(程序启动时)预取号失败:

R: 预取号方法会先调用系统API检测当前手机流量对应的运营商,而在程序刚刚启动时,该检测方法往往会检测不到正确的运营商

A: 把预取号的方法放到 - (BOOL)application:(UIApplication)application didFinishLaunchingWithOptions:(NSDictionary)launchOptions 方法的最后面执行,或者稍微延迟一下去执行预取号方法