开发者中心

概述


当前最新版本:2.3.4.1
常见问题请移步至「对接问题」
崩溃问题请移步至「崩溃问题」
版本升级:详细说明请移步至「升级指南

**注:用户iOS APP如使用了RSA加密,建议将读写RSA秘钥的tag值设置成自己公司命名规范字符串,尽量保证tag值在APP内唯一,如:NSString *tag = **“com_253_shanyan_RSA…Key”;

一.准备工作

版本升级提示(重要):

  • 如项目中使用闪验vcclass的字符串判断类名等非常规操作,如"ZUOAuthViewController"、“UAAuthViewController”、“PublicLoginViewController”、“CLCTCCCarouselViewController”、“CLCTCCCarouselNavigationController”、“UANavigationController”、“CLCTCCPublicLoginNavigationController”、“CLShanYanAuthPageIsaSwizzleNavigationController”,现已统一为:CLShanYanAuthPageNavigationController(授权页nav)、CLShanYanAuthPageViewController(授权页vc)、CLCTCCCarouselNavigationController(弹窗模式下协议页nav)、CLCTCCCarouselViewController(协议页vc)
  • 现sdk回调默认为全局global队列,如需UI操作请务必自行切换到主线程

前置条件

  • 闪验SDK支持Xcode 11+打包,iOS8.0+及以上版本。
  • 闪验SDK支持中国移动、联通、电信4G的取号能力。
  • 闪验SDK支持网络环境为

a.纯数据网络
      b.数据网络与wifi网络双开

  • 对于双卡手机,闪验SDK取当前流量卡号

一键登录使用场景:
用户无需输入手机号码,只需集成并调用SDK拉起授权页方法,用户确认授权后,SDK会获取token,服务端携带token到运营商网关获取用户当前上网使用的流量卡号码,并返回给APP服务端。

本机号码校验(本机认证)使用场景:
用户通过SDK获取token,服务端携带手机号码和token去运营商网关进行校验比对,返回的校验结果为:用户当前流量卡号码与服务端携带的手机号码是否一致。

创建应用

**
应用的创建流程及APPID/APPKEY的获取,请查看「账号创建」文档

快速体验Demo

将创建应用时获得的AppID填入Demo工程中.pch文件,修改工程BundleID为创建应用时绑定的BundleID即可

开发环境搭建

闪验SDK提供两种集成方式供iOS开发者选择:

  • 通过CocoaPods自动集成
  • 手动集成

通过CocoaPods自动集成
在工程的Podfile里面添加以下代码:以下示例pod 版本仅供参考,请按需选择或选择最新版本

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

#集成最新版闪验SDK:
pod 'CL_ShanYanSDK'

#集成指定版本闪验SDK:
pod 'CL_ShanYanSDK', '2.3.3.9'

#集成指定版本闪验SDK,并在末位小版本范围更新:
pod 'CL_ShanYanSDK', '~> 2.3.3.0'

保存并执行pod install,然后用后缀为.xcworkspace的文件打开工程。
注意:
命令行下执行pod search CL_ShanYanSDK,如显版本不是最新版,或者pod install导入的版本不是最新版,则先执行pod repo update操作更新本地repo的内容
如无法更新到最新版本,请先清空缓存: pod cache clean --all & pod repo update & pod install
关于CocoaPods的更多信息请查看 CocoaPods官方网站

手动集成

  1. 导入framework: 将闪验SDK压缩包中framework文件夹下所有资源添加到工程中(注意勾选Copy items if needed)

导入资源文件1.jpg

  1. Xcode配置:
  • OtherLinkerFlags中 添加-ObjC****:xcode->BuildSetting->Other Linker Flags 添加 -ObjC

otherLink-ObjC.jpg

  • 添加libc++.1.tbd: 在xcode->General->Linked Frameworks and Libraries中点击 + ,搜索并选择添加 libc++.1.tbd

libc++.1.tbd.jpg

  1. Swift工程需要额外添加-force_load:
  • 在xcode->BuildSetting->Other Linker Flags 添加-force_load

swift-force_load.jpg

  • 在-force_load下方添加CL_ShanYanSDK.framework/CL_ShanYanSDK所在路径,具体操作可以将CL_ShanYanSDK.framework拖入空栏,在尾部拼接静态库名称CL_ShanYanSDK,将前缀绝对地址改成相对地址$(SRCROOT),最终为 "$(SRCROOT)/…/CL_ShanYanSDK.framework/CL_ShanYanSDK"形式

swift-sdk-path.jpg

二.SDK使用说明

1.初始化

方法原型

/**初始化*/
+(void)initWithAppId:(NSString *)appId complete:(nullable CLComplete)complete;

参数描述

参数 是否必填 类型 说明
appId 必填 NSString 闪验appID
complete 选填 CLComplete 初始化回调block,可以在此回调block中接收初始化情况,也可以不关心初始化结果

接口作用

初始化SDK :传入用户的appId,请求闪验服务接口以获取运营商配置信息,接口请求成功缓存相关信息

使用场景

  • 在app启动时进行调用
  • 保证在预取号或一键登录前至少调用一次
  • 只需调用一次,多次调用不会多次初始化,与一次调用效果一致

请求示例代码

ObjC:

  1. 导入闪验SDK头文件 #import <CL_ShanYanSDK/CL_ShanYanSDK.h>
  2. 在AppDelegate中的 didFinishLaunchingWithOptions方法中添加初始化代码
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    ...
    //初始化
    [CLShanYanSDKManager initWithAppId:cl_SDK_APPID complete:nil];
    
    /**
     * 建议在退出登录时再次调用初始化方法
     */
    ...
}

Swift:

  1. 创建混编桥接头文件并导入闪验SDK头文件 #import <CL_ShanYanSDK/CL_ShanYanSDK.h>
  2. 在AppDelegate中的 didFinishLaunchingWithOptions方法中添加初始化代码
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    ...
    //初始化
    CLShanYanSDKManager.initWithAppId("your appId") { (completeResult) in
        if ((completeResult.error) != nil) {
            print("初始化失败")
        } else {
            print("初始化成功")
        }
    }
    ...
}

2.预取号

不建议 频繁的多次调用和在拉起授权页后调用

预取号方法回调中处理UI操作需手动切换到主线程

方法原型

/**
 * 预取号
 * 此调用将有助于提高闪验拉起授权页的速度和成功率
 * 建议在一键登录前提前调用此方法,比如调一键登录的vc的viewdidload中、初始化成功的回调中
 * 不建议在拉起授权页后调用
 * 回调中如需UI操作,建议自行切到主线程
 */
+(void)preGetPhonenumber:(nullable CLComplete)complete;

接口作用

电信、联通、移动预取号 :初始化成功后,如果当前为电信/联通/移动,将调用预取号,可以提前获知当前用户的手机网络环境是否符合一键登录的使用条件,成功后将得到用于一键登录使用的临时凭证,默认的凭证有效期60min(三大运营商一致)。

使用场景

  • 建议在执行一键登录的方法前,提前一段时间调用此方法,比如调一键登录的vc的viewdidload中,或者rootVC的viewdidload中,或者app启动后,此调用将有助于提高闪验拉起授权页的速度和成功率
  • 不建议调用后立即调用拉起授权页方法(此方法是异步)
  • 此方法需要1~2s的时间取得临时凭证,因此也不建议和拉起授权页方法一起串行调用
  • 不建议频繁的多次调用和在拉起授权页后调用
  • 建议在判断当前用户属于未登录状态时使用,已登录状态用户请不要调用该方法

请求示例代码

ObjC:

#import <CL_ShanYanSDK/CL_ShanYanSDK.h>
//开发者调拉起授权页的vc
@implementation CustomLoginViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    if (YourAppLoginStatus == NO) {
        //预取号
        [CLShanYanSDKManager preGetPhonenumber:nil];
        ...
    }
}
...
//拉起授权页
- (void)shanYanAuthPageLogin{
    ...
}

3.拉起授权页

在预取号成功后调用,预取号失败不建议调用。调用拉起授权页方法后将会调起运营商授权页面。该方法会拉起登录界面,已登录状态请勿调用 。

/**
 一键登录 区分拉起授权页之前和之后的回调
 
 @param clUIConfigure 闪验授权页参数配置
 @param openLoginAuthListener 拉起授权页监听:拉起授权页面成功或失败的回调,拉起成功或失败均触发。当拉起失败时,oneKeyLoginListener不会触发。此回调的内部触发时机是viewDidAppear
                    
 @param oneKeyLoginListener 一键登录监听:拉起授权页成功后的后续操作回调,包括点击SDK内置的(非外部自定义)取消登录按钮,以及点击本机号码一键登录的回调。点击授权页自定义按钮不触发此回调
 
 * 回调中如需UI操作,建议自行切到主线程
 */
+(void)quickAuthLoginWithConfigure:(CLUIConfigure *)clUIConfigure
             openLoginAuthListener:(CLComplete)openLoginAuthListener
               oneKeyLoginListener:(CLComplete)oneKeyLoginListener;

参数描述

参数 类型 说明
clUIConfigure  必填 CLUIConfigure 授权页控件属性配置对象
openLoginAuthListener  选填 CLComplete 拉起授权页的回调,拉起页面成功、失败均触发
注意:在此回调中用户UI操作必须手动切换到主线程
oneKeyLoginListener 必填 CLComplete 一键登录回调,用于接收一键登录的结果,点一键登录成功、失败均触发,点自带的返回按钮也触发

使用场景

  • 用户进行一键登录操作时,调用一键登录方法,如果初始化成功,SDK将会拉起授权页面,用户授权后,SDK将返回取号 token给到应用客户端。
  • 可以在多处调用
  • 需在调用预初始化方法之后调用

一键登录逻辑说明

  • 存在调用预初始化时获取的临时凭证,调用一键登录方法将立即拉起授权页面
  • openLoginAuthListener: 拉起授权页面成功或失败的回调,拉起成功或失败均触发。当拉起失败时,oneKeyLoginListener不会触发。此回调的内部触发时机是viewDidAppear
  • oneKeyLoginListener:一键登录监听, 拉起授权页成功后的后续操作回调,包括点击SDK内置的(非外部自定义)取消登录按钮,以及点击本机号码一键登录的回调。点击授权页自定义按钮不触发此回调
  • 不存在临时凭证或临时凭证过期时(临时凭证有效期电信60min、联通60min、移动60min),调用一键登录方法,将有一个很短的时延,待取号成功后拉起授权页面
  • 取号失败时,返回失败

请求示例代码

ObjC:

  1. 导入闪验SDK头文件 #import <CL_ShanYanSDK/CL_ShanYanSDK.h>
  2. 在需要使用一键登录的地方调用闪验一键登录接口
// 用户需要使用闪验一键登录时的方法
- (void)quickLoginBtnClick:(UIButton *)sender {

    __weak typeof(self) weakself = self;

    CGFloat screenScale = [UIScreen mainScreen].bounds.size.width/375.0;

    CLUIConfigure * baseUIConfigure = [CLUIConfigure new];
    baseUIConfigure.viewController = self;
    baseUIConfigure.clLogoImage = [UIImage imageNamed:@"your_app_logo_image"];
    
    baseUIConfigure.clAppPrivacyFirst = @[@"闪验测试连接1",[NSURL URLWithString:@"https://baidu.com"]];
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"ShanYanIndex" ofType:@"html"];
    //baseUIConfigure.clAppPrivacySecond = @[@"闪验测试连接2",[NSURL URLWithString:@"https://sina.com"]];
	baseUIConfigure.clAppPrivacySecond = @[@"本地协议地址",[NSURL fileURLWithPath:filePath]];
    
    //layout 布局
    CLOrientationLayOut * clOrientationLayOutPortrait = [CLOrientationLayOut new];
    clOrientationLayOutPortrait.clLayoutPhoneCenterY = @(0*screenScale);
    clOrientationLayOutPortrait.clLayoutPhoneLeft = @(50*screenScale);
    ...
    baseUIConfigure.clOrientationLayOutPortrait = clOrientationLayOutPortrait;
    
	// show loading...

    //闪验一键登录接口(将拉起授权页)
    [CLShanYanSDKManager quickAuthLoginWithConfigure:baseUIConfigure openLoginAuthListener:^(CLCompleteResult * _Nonnull completeResult) {
            // hide loading...
            if (completeResult.error) {
                //拉起授权页失败
                NSLog(@"openLoginAuthListener:%@",completeResult.error.userInfo);
            }else{
               //拉起授权页成功
                NSLog(@"openLoginAuthListener:%@",completeResult.yy_modelToJSONObject);
            }
        } oneKeyLoginListener:^(CLCompleteResult * _Nonnull completeResult) {
            __strong typeof(self) strongSelf = weakSelf;

            if (completeResult.error) {
                //一键登录失败
                NSLog(@"oneKeyLoginListener:%@",completeResult.error.description);
                
                //提示:错误无需提示给用户,可以在用户无感知的状态下直接切换登录方式
                if (completeResult.code == 1011){
                    //用户取消登录(点返回)
                    //处理建议:如无特殊需求可不做处理,仅作为交互状态回调,此时已经回到当前用户自己的页面
                    //点击sdk自带的返回,无论是否设置手动销毁,授权页面都会强制关闭
                }  else{
                    //处理建议:其他错误代码表示闪验通道无法继续,可以统一走开发者自己的其他登录方式,也可以对不同的错误单独处理
                    //关闭授权页,如果授权页还未拉起,此调用不会关闭当前用户vc,即不执行任何代码
                    [CLShanYanSDKManager finishAuthControllerCompletion:nil];
                }
            }else{
                //一键登录获取Token成功
                NSLog(@"oneKeyLoginListener:%@",completeResult.yy_modelDescription);
                
                //SDK成功获取到Token
                /** token置换手机号
                code
                */
            }
        }];
 }

**一键登录 ****quickAuthLoginWith:complete:**正确返回示例

返回参数示例 completeResult.data
{
	token = "A3-KqvM4yO_lApRLwpv4qVNnBRF3w=="
}
字段 类型 含义
token String token,置换令牌,用来和后台置换手机号。一次有效,有效期3min

**一键登录 ****quickAuthLoginWith:complete:**报错处理

completeResult->_error:

  • 用户取消登录(授权页点击返回) 【处理建议:若无特殊需求可不做处理】
  • 用户选择其他方式登录(点击授权页自带的其他方式登录): 【处理建议:可根据实际情况跳转其他登录方式 】
  • 其他错误 【处理建议:使用闪验通道失败,可根据实际情况跳转其他登录方式 】

授权页销毁

注:sdk拉起授权页成功后,只允许点击一次一键登录按钮。一键登录按钮点击一次后,只有sdk自带的左上角返回按钮可以交互,效果为强制关闭授权页,其他页面元素均会被禁用,以防止多次点击导致多次回调而出现异常。

拉起授权页前 配置授权页面销毁机制属性

// 获取默认参数配置
CLUIConfigure * baseUIConfigure = [CLUIConfigure clDefaultUIConfigure];
baseUIConfigure.viewController = self;
// 是否需要手动销毁授权页面,默认自动销毁, YES->手动销毁
baseUIConfigure.manualDismiss = @(YES);

sdk获取token回调后销毁界面

//关闭页面
[CLShanYanSDKManager finishAuthControllerCompletion:^{
   //如需关闭后present/push新页面,建议在completion回调中执行
	//注:若未拉起授权页,调用此方法,block不会触发
    //用户跳转短信验证
    CustomSmsViewController * smsVc = [[CustomSmsViewController alloc]init];
    CustomNavigationController * smsNav = [[CustomNavigationController alloc]initWithRootViewController:smsVc];
    smsVc.navigationItem.title = @"短信验证";
    [self presentViewController:smsNav animated:YES completion:nil];
}];

4.置换手机号

**注:移动、联通、电信分别有自己的置换手机号url,需要根据相对应的运营商url置换手机号码。详情见下方 ****请求示例代码**

使用场景

SDK成功返回token后,开发者需自行调用置换手机号接口,此接口需要开发者调用由服务端接入闪验服务端生成的接口,上线前的调试阶段可以直接使用示例代码中的接口

请求示例代码

ObjC:

[CLShanYanSDKManager quickAuthLoginWithConfigure:baseUIConfigure openLoginAuthListener:^(CLCompleteResult * _Nonnull completeResult) {
    // UI操作建议手动切至主线程
    if (completeResult.error) {
        //拉起授权页失败
        NSLog(@"openLoginAuthListener:%@",completeResult.error.userInfo);
    }else{
       //拉起授权页成功
        NSLog(@"openLoginAuthListener:%@",completeResult.yy_modelToJSONObject);
    }
} oneKeyLoginListener:^(CLCompleteResult * _Nonnull completeResult) {
    [SVProgressHUD dismiss];
    if (completeResult.error) {
      	...
    }else{
      	//SDK成功获取到Token
      
        请求用户APP服务端置换手机号
    }
}];

Swift:

CLShanYanSDKManager.quickAuthLogin(with: clUIConfigure, openLoginAuthListener: { (completeResult) in
    ...
}) { (completeResult) in 

    if completeResult.error != nil {
        ...
    }else{
      //SDK成功获取到Token

        NSLog("quickAuthLogin Success:%@",completeResult.data ?? "")

        请求用户APP服务端置换手机号
    }
  }
}

4.手动关闭授权页

当开发者设置点击一键登录或者自定义控件不自动销毁授权页时,将需要自行调用此方法主动销毁授权页,建议在置换手机号成功后销毁。如在得到回调后未销毁授权页而,使用拉起授权页方法再次拉起授权页,此页面将无法响应任何按键(除了导航栏的返回按钮)。

  • 关闭授权页时机

a.SDK拉起授权页方法 直接回调失败时
      b.置换手机号有返回结果时

  • 当前页面直接销毁
//方式1
[self.PresentedViewController dismissViewControllerAnimated:YES completion:nil];

//方式二
[CLShanYanSDKManager finishAuthControllerCompletion:^{
   //如需关闭后present/push新页面,建议在completion回调中执行
	//注:若未拉起授权页,调用此方法,block不会触发
    //用户跳转短信验证
    CustomSmsViewController * smsVc = [[CustomSmsViewController alloc]init];
    CustomNavigationController * smsNav = [[CustomNavigationController alloc]initWithRootViewController:smsVc];
    smsVc.navigationItem.title = @"短信验证";
    [self presentViewController:smsNav animated:YES completion:nil];
}];
  • 找到topVC进行dismiss
dispatch_async(dispatch_get_main_queue(), ^{
    //建议使用授权页面配置对象传入的viewcontroller 调 dismiss
    if (self.navigationController.viewControllers.lastObject.navigationController) {
        [self.navigationController.viewControllers.lastObject dismissViewControllerAnimated:YES completion:nil];
    } else {
        UIViewController *topRootViewController = [[UIApplication  sharedApplication] keyWindow].rootViewController;
        // 在这里加一个这个样式的循环
        while (topRootViewController.presentedViewController) {
            // 这里固定写法
            topRootViewController = topRootViewController.presentedViewController;
        }
        // 然后再进行present操作
        [topRootViewController dismissViewControllerAnimated:YES completion:nil];
    }
});

5.登录按钮、协议、勾选框控件点击监听

控件点击的监听是通过代理实现,在授权页面显示前触发代理进行监听。不监听协议点击可不实现代理,按需配置。
注意实现协议:@interface xxxController ()

在拉起授权页之前设置代理

//弹窗添加蒙版或点击协议回调 代理设置,不监听协议点击或不使用蒙版可不设置代理
[CLShanYanSDKManager setCLShanYanSDKManagerDelegate:self];

一键登录按钮、协议、勾选框点击监听

/**
 * 统一事件监听方法
 * type:事件类型(1,2,3)
 * 1:隐私协议点击
 * - 同-clShanYanSDKManagerWebPrivacyClicked:privacyIndex:currentTelecom
 * code:0,1,2,3(协议页序号),message:协议名_当前运营商类型
 * 2:协议勾选框点击
 * code:0,1(0为未选中,1为选中)
 * 3:"一键登录"按钮点击
 * code:0,1(0为协议勾选框未选中,1为选中)
 * UI操作建议手动切至主线程
*/
-(void)clShanYanActionListener:(NSInteger)type code:(NSInteger)code  message:(NSString *_Nullable)message;

协议点击监听方式二

#pragma mark - CLShanYanSDKManagerDelegate
- (void)clShanYanSDKManagerWebPrivacyClicked:(NSString *)privacyName privacyIndex:(NSInteger)index currentTelecom:(NSString *)telecom{
    NSLog(@"协议名称:%@---协议位置:%lu---当前运营商:%@",privacyName,index,telecom);
}

6.多次点击一键登录按钮、手动关闭授权页面上的loading

使用场景:授权页面“一键登录”按钮点击后oneKeyLoginListener失败回调中或用户APP端向服务端置换手机号码接口失败回调中调用该方法,以达到隐藏loading 再次点击"一键登录"按钮的效果(按钮最多只能被点击4次)。

// 隐藏授权页面上的loading框
+(void)hideLoading;

三.授权界面修改

1.设计规范

规范.jpg

开发者不得通过任何技术手段,将授权页面的隐私栏、品牌露出内容隐藏、覆盖,对于接入闪验SDK并上线的应用,我方和运营商会对上线的应用授权页面做审查,如果有出现未按要求设计授权页面,将隐私栏、运营商品牌、授权登录按钮隐去不可见的设计,我方有权将应用的登录功能下线。

2.页面可调整属性

注:授权页基本控件均支持上、下、左、右、宽、高、水平中心、竖直中心布局设置,布局通过布局对象设置,布局定位更加方便快捷,建议使用最新布局对象进行设置。每个控件对象需要设置4个方向上的数值。

注:2.3.1.1版本开始更新隐私协议控件,提高点击响应灵敏度。隐私协议控件由UITextView更换为UILabel控件,
删除隐私协议 clAppPrivacyLineFragmentPaddingclAppPrivacyContentInset属性,目前只要设置clAppPrivacyTextContainerInset属性即可达到设置文本内边距的效果

//要拉起授权页的vc [必填项] (注:SDK不持有接入方VC)
@property (nonatomic,weak)UIViewController * viewController;

/**
 *外部手动管理关闭界面
 *BOOL,default is NO
 *eg.@(YES)
 */
@property (nonatomic,strong)NSNumber * manualDismiss;

/**授权页-背景图片*/
@property (nonatomic,strong) UIImage *clBackgroundImg;

//导航栏
/**导航栏 是否隐藏 BOOL default is NO, 设置优先级高于clNavigationBackgroundClear eg.@(NO)*/
@property (nonatomic,strong)NSNumber * clNavigationBarHidden;
/**导航栏 背景透明 BOOL eg.@(YES)*/
@property (nonatomic,strong)NSNumber * clNavigationBackgroundClear;
/**导航栏标题*/
@property (nonatomic,strong)NSAttributedString * clNavigationAttributesTitleText;

/**导航栏右侧自定义按钮*/
@property (nonatomic,strong)UIBarButtonItem * clNavigationRightControl;
/**导航栏左侧自定义按钮*/
@property (nonatomic,strong)UIBarButtonItem * clNavigationLeftControl;

// 返回按钮
/**导航栏左侧返回按钮图片*/
@property (nonatomic,strong)UIImage   * clNavigationBackBtnImage;
/**导航栏自带返回按钮隐藏,默认显示 BOOL eg.@(YES)*/
@property (nonatomic,strong)NSNumber  * clNavigationBackBtnHidden;
/**************新增******************/
/**返回按钮图片缩进 btn.imageInsets = UIEdgeInsetsMake(0, 0, 20, 20)*/
@property (nonatomic,strong)NSValue * clNavBackBtnImageInsets;
/**自带返回(关闭)按钮位置 默认NO 居左,设置为YES居右显示*/
@property (nonatomic,strong)NSNumber * clNavBackBtnAlimentRight;

/*translucent 此属性已失效*/
//@property (nonatomic,strong)NSNumber * cl_navigation_translucent;

/**导航栏分割线 是否隐藏
 * set backgroundImage=UIImage.new && shadowImage=UIImage.new
 * BOOL, default is NO
 * eg.@(YES)
 */
@property (nonatomic,strong)NSNumber * clNavigationBottomLineHidden;
/**导航栏 文字颜色*/
@property (nonatomic,strong)UIColor  * clNavigationTintColor;
/**导航栏 背景色 default is white*/
@property (nonatomic,strong)UIColor  * clNavigationBarTintColor;
/**导航栏 背景图片*/
@property (nonatomic,strong)UIImage  * clNavigationBackgroundImage;
/**导航栏 配合背景图片设置,用来控制在不同状态下导航栏的显示(横竖屏是否显示) UIBarMetrics eg.@(UIBarMetricsCompact)*/
@property (nonatomic,strong)NSNumber * clNavigationBarMetrics;
/**导航栏 导航栏底部分割线(图片)*/
@property (nonatomic,strong)UIImage  * clNavigationShadowImage;


/*状态栏样式
 *Info.plist: View controller-based status bar appearance = YES
 *
 *UIStatusBarStyleDefault:状态栏显示 黑
 *UIStatusBarStyleLightContent:状态栏显示 白
 *UIStatusBarStyleDarkContent:状态栏显示 黑 API_AVAILABLE(ios(13.0)) = 3
 **eg. @(UIStatusBarStyleLightContent)
 */
@property (nonatomic,strong)NSNumber * clPreferredStatusBarStyle;
/*状态栏隐藏 eg.@(NO)*/
@property (nonatomic,strong)NSNumber * clPrefersStatusBarHidden;

/**
 *NavigationBar.barStyle:默认UIBarStyleBlack
 *Info.plist: View controller-based status bar appearance = YES

 *UIBarStyleDefault:状态栏显示 黑
 *UIBarStyleBlack:状态栏显示 白
 *
 *eg. @(UIBarStyleBlack)
 */
@property (nonatomic,strong)NSNumber * clNavigationBarStyle;



//LOGO图片
/**LOGO图片*/
@property (nonatomic,strong)UIImage  * clLogoImage;
/**LOGO圆角 CGFloat eg.@(2.0)*/
@property (nonatomic,strong)NSNumber * clLogoCornerRadius;
/**LOGO显隐 BOOL eg.@(NO)*/
@property (nonatomic,strong)NSNumber * clLogoHiden;

/**手机号显示控件*/
/**手机号颜色*/
@property (nonatomic,strong)UIColor  * clPhoneNumberColor;
/**手机号字体*/
@property (nonatomic,strong)UIFont   * clPhoneNumberFont;
/**手机号对齐方式 NSTextAlignment eg.@(NSTextAlignmentCenter)*/
@property (nonatomic,strong)NSNumber * clPhoneNumberTextAlignment;

/*一键登录按钮 控件
 注: 一键登录授权按钮 不得隐藏
 **/
/**按钮文字*/
@property (nonatomic,copy)NSString   * clLoginBtnText;
/**按钮文字颜色*/
@property (nonatomic,strong)UIColor  * clLoginBtnTextColor;
/**按钮背景颜色*/
@property (nonatomic,strong)UIColor  * clLoginBtnBgColor;
/**按钮文字字体*/
@property (nonatomic,strong)UIFont   * clLoginBtnTextFont;
/**按钮背景图片*/
@property (nonatomic,strong)UIImage  * clLoginBtnNormalBgImage;
/**按钮背景高亮图片*/
@property (nonatomic,strong)UIImage  * clLoginBtnHightLightBgImage;
/**按钮背景不可用图片*/
@property (nonatomic,strong)UIImage  * clLoginBtnDisabledBgImage;
/**按钮边框颜色*/
@property (nonatomic,strong)UIColor  * clLoginBtnBorderColor;
/**按钮圆角 CGFloat eg.@(5)*/
@property (nonatomic,strong)NSNumber * clLoginBtnCornerRadius;
/**按钮边框 CGFloat eg.@(2.0)*/
@property (nonatomic,strong)NSNumber * clLoginBtnBorderWidth;

/*隐私条款Privacy
 注: 运营商隐私条款 不得隐藏
 用户条款不限制
 **/
/**隐私条款 下划线设置,默认隐藏,设置clPrivacyShowUnderline = @(YES)显示下划线*/
@property (nonatomic,strong)NSNumber * clPrivacyShowUnderline;
/**隐私条款名称颜色:@[基础文字颜色UIColor*,条款颜色UIColor*] eg.@[[UIColor lightGrayColor],[UIColor greenColor]]*/
@property (nonatomic,strong) NSArray<UIColor*> *clAppPrivacyColor;
/**隐私条款文字字体*/
@property (nonatomic,strong)UIFont  * clAppPrivacyTextFont;
/**隐私条款文字对齐方式 NSTextAlignment eg.@(NSTextAlignmentCenter)*/
@property (nonatomic,strong)NSNumber * clAppPrivacyTextAlignment;
/**运营商隐私条款书名号 默认NO 不显示 BOOL eg.@(YES)*/
@property (nonatomic,strong)NSNumber * clAppPrivacyPunctuationMarks;
/**多行时行距 CGFloat eg.@(2.0)*/
@property (nonatomic,strong)NSNumber* clAppPrivacyLineSpacing;
/**是否需要sizeToFit,设置后与宽高约束的冲突请自行考虑 BOOL eg.@(YES)*/
@property (nonatomic,strong)NSNumber* clAppPrivacyNeedSizeToFit;
/**UITextView.textContainerInset 文字与TextView控件内边距 UIEdgeInset  eg.[NSValue valueWithUIEdgeInsets:UIEdgeInsetsMake(2, 2, 2, 2)]*/
@property (nonatomic,strong)NSValue* clAppPrivacyTextContainerInset;
/**隐私条款--APP名称简写 默认取CFBundledisplayname 设置描述文本四后此属性无效*/
@property (nonatomic,copy) NSString  * clAppPrivacyAbbreviatedName;
/*
 *隐私条款Y一:需同时设置Name和UrlString eg.@[@"条款一名称",条款一URL]
 *@[NSSting,NSURL];
 */
@property (nonatomic,strong)NSArray * clAppPrivacyFirst;
/*
 *隐私条款二:需同时设置Name和UrlString eg.@[@"条款一名称",条款一URL]
 *@[NSSting,NSURL];
 */
@property (nonatomic,strong)NSArray * clAppPrivacySecond;
/*
 *隐私条款三:需同时设置Name和UrlString eg.@[@"条款一名称",条款一URL]
 *@[NSSting,NSURL];
 */
@property (nonatomic,strong)NSArray * clAppPrivacyThird;
/*
 隐私协议文本拼接: DesTextFirst+运营商条款+DesTextSecond+隐私条款一+DesTextThird+隐私条款二+DesTextFourth+隐私条款三+DesTextLast
 **/
/**描述文本 首部 default:"同意"*/
@property (nonatomic,copy)NSString *clAppPrivacyNormalDesTextFirst;
/**描述文本二 default:"和"*/
@property (nonatomic,copy)NSString *clAppPrivacyNormalDesTextSecond;
/**描述文本三 default:"、"*/
@property (nonatomic,copy)NSString *clAppPrivacyNormalDesTextThird;
/**描述文本四 default:"、"*/
@property (nonatomic,copy)NSString *clAppPrivacyNormalDesTextFourth;
/**描述文本 尾部 default: "并授权AppName使用认证服务"*/
@property (nonatomic,copy)NSString *clAppPrivacyNormalDesTextLast;

/**运营商协议后置 默认@(NO)"*/
@property (nonatomic,strong)NSNumber *clOperatorPrivacyAtLast;

/**用户隐私协议WEB页面导航栏标题 默认显示用户条款名称*/
@property (nonatomic,strong)NSAttributedString * clAppPrivacyWebAttributesTitle;
/**自定义协议标题-按自定义协议对应顺序*/
@property (nonatomic,strong)NSArray<NSString*> * clAppPrivacyWebTitleList;
/**运营商隐私协议WEB页面导航栏标题 默认显示运营商条款名称*/
@property (nonatomic,strong)NSAttributedString * clAppPrivacyWebNormalAttributesTitle;
/**隐私协议标题文本属性(用户协议&&运营商协议)*/
@property (nonatomic,strong)NSDictionary * clAppPrivacyWebAttributes;
/**隐私协议WEB页面导航返回按钮图片*/
@property (nonatomic,strong)UIImage * clAppPrivacyWebBackBtnImage;

/*协议页状态栏样式 默认:UIStatusBarStyleDefault*/
@property (nonatomic,strong)NSNumber * clAppPrivacyWebPreferredStatusBarStyle;

/**UINavigationTintColor*/
@property (nonatomic,strong)UIColor  * clAppPrivacyWebNavigationTintColor;
/**UINavigationBarTintColor*/
@property (nonatomic,strong)UIColor  * clAppPrivacyWebNavigationBarTintColor;
/**UINavigationBackgroundImage*/
@property (nonatomic,strong)UIImage  * clAppPrivacyWebNavigationBackgroundImage;
/**UINavigationBarMetrics*/
@property (nonatomic,strong)NSNumber * clAppPrivacyWebNavigationBarMetrics;
/**UINavigationShadowImage*/
@property (nonatomic,strong)UIImage  * clAppPrivacyWebNavigationShadowImage;
/**UINavigationBarStyle*/
@property (nonatomic,strong)NSNumber * clAppPrivacyWebNavigationBarStyle;

/*SLOGAN
 注: 运营商品牌标签("中国**提供认证服务"),不得隐藏
 **/
/**slogan文字字体*/
@property (nonatomic,strong) UIFont   * clSloganTextFont;
/**slogan文字颜色*/
@property (nonatomic,strong) UIColor  * clSloganTextColor;
/**slogan文字对齐方式 NSTextAlignment eg.@(NSTextAlignmentCenter)*/
@property (nonatomic,strong) NSNumber * clSlogaTextAlignment;

/*闪验SLOGAN
 注: 供应商品牌标签("闪验提供认技术支持")
 **/
/**slogan文字字体*/
@property (nonatomic,strong) UIFont   * clShanYanSloganTextFont;
/**slogan文字颜色*/
@property (nonatomic,strong) UIColor  * clShanYanSloganTextColor;
/**slogan文字对齐方式 NSTextAlignment eg.@(NSTextAlignmentCenter)*/
@property (nonatomic,strong) NSNumber * clShanYanSloganTextAlignment;
/**slogan默认不隐藏 eg.@(NO)*/
@property (nonatomic,strong) NSNumber  * clShanYanSloganHidden;

/*CheckBox
 *协议勾选框,默认选中且在协议前显示
 *可在sdk_oauth.bundle中替换checkBox_unSelected、checkBox_selected图片
 *也可以通过属性设置选中和未选择图片
 **/
/**协议勾选框(默认显示,放置在协议之前)BOOL eg.@(YES)*/
@property (nonatomic,strong) NSNumber *clCheckBoxHidden;
/**协议勾选框默认值(默认选中)BOOL eg.@(YES)*/
@property (nonatomic,strong) NSNumber *clCheckBoxValue;
/**协议勾选框 尺寸 NSValue->CGSize eg.[NSValue valueWithCGSize:CGSizeMake(25, 25)]*/
@property (nonatomic,strong) NSValue *clCheckBoxSize;
/**协议勾选框 UIButton.image图片缩进 UIEdgeInset eg.[NSValue valueWithUIEdgeInsets:UIEdgeInsetsMake(2, 2, 2, 2)]*/
@property (nonatomic,strong) NSValue *clCheckBoxImageEdgeInsets;
/**协议勾选框 设置CheckBox顶部与隐私协议控件顶部对齐 YES或大于0生效 eg.@(YES)*/
@property (nonatomic,strong) NSNumber *clCheckBoxVerticalAlignmentToAppPrivacyTop;

/**协议勾选框 设置CheckBox对齐后的偏移量,相对于对齐后的中心距离在当前垂直方向上的偏移*/
@property (nonatomic,strong) NSNumber *clCheckBoxVerticalAlignmentOffset;

/**协议勾选框 设置CheckBox顶部与隐私协议控件竖向中心对齐 YES或大于0生效 eg.@(YES)*/
@property (nonatomic,strong) NSNumber *clCheckBoxVerticalAlignmentToAppPrivacyCenterY;
/**协议勾选框 非选中状态图片*/
@property (nonatomic,strong) UIImage  *clCheckBoxUncheckedImage;
/**协议勾选框 选中状态图片*/
@property (nonatomic,strong) UIImage  *clCheckBoxCheckedImage;


/**授权页自定义 "请勾选协议"提示框
 - containerView为loading的全屏蒙版view
 - 请自行在containerView添加自定义loading
 - 设置block后,上述loading属性将无效
 */
@property (nonatomic,copy)void(^checkBoxTipView)(UIView * containerView);
/**checkBox 未勾选时 提示文本,默认:"请勾选协议"*/
@property (nonatomic,copy) NSString *clCheckBoxTipMsg;
/**使用sdk内部“一键登录”按钮点击时的吐丝提示("请勾选协议")
 * NO:默认使用sdk内部吐丝 YES:禁止使用
 */
@property (nonatomic,strong) NSNumber *clCheckBoxTipDisable;


/*Loading*/
/**Loading 大小 CGSize eg.[NSValue valueWithCGSize:CGSizeMake(50, 50)]*/
@property (nonatomic,strong) NSValue *clLoadingSize;
/**Loading 圆角 float eg.@(5) */
@property (nonatomic,strong) NSNumber *clLoadingCornerRadius;
/**Loading 背景色 UIColor eg.[UIColor colorWithRed:0.8 green:0.5 blue:0.8 alpha:0.8]; */
@property (nonatomic,strong) UIColor *clLoadingBackgroundColor;
/**UIActivityIndicatorViewStyle eg.@(UIActivityIndicatorViewStyleWhiteLarge)*/
@property (nonatomic,strong) NSNumber *clLoadingIndicatorStyle;
/**Loading Indicator渲染色 UIColor eg.[UIColor greenColor]; */
@property (nonatomic,strong) UIColor *clLoadingTintColor;
/**授权页自定义Loading
 - containerView为loading的全屏蒙版view
 - 请自行在containerView添加自定义loading
 - 设置block后,上述loading属性将无效
 */
@property (nonatomic,copy)void(^loadingView)(UIView * containerView);

//添加自定义控件
/**可设置背景色及添加控件*/
@property (nonatomic,copy)void(^customAreaView)(UIView * customAreaView);
/**设置隐私协议弹窗*/
@property (nonatomic,copy)void(^customPrivacyAlertView)(UIViewController * authPageVC);

/**横竖屏*/
/*是否支持自动旋转 BOOL*/
@property (nonatomic,strong) NSNumber * shouldAutorotate;
/*支持方向 UIInterfaceOrientationMask
 - 如果设置只支持竖屏,只需设置clOrientationLayOutPortrait竖屏布局对象
 - 如果设置只支持横屏,只需设置clOrientationLayOutLandscape横屏布局对象
 - 横竖屏均支持,需同时设置clOrientationLayOutPortrait和clOrientationLayOutLandscape
 */
@property (nonatomic,strong) NSNumber * supportedInterfaceOrientations;
/*默认方向 UIInterfaceOrientation*/
@property (nonatomic,strong) NSNumber * preferredInterfaceOrientationForPresentation;

/**以窗口方式显示授权页
 */
/**以窗口方式显示 BOOL, default is NO */
@property (nonatomic,strong) NSNumber * clAuthTypeUseWindow;
/**窗口圆角 float*/
@property (nonatomic,strong) NSNumber * clAuthWindowCornerRadius;

/**clAuthWindowModalTransitionStyle系统自带的弹出方式 仅支持以下三种
 UIModalTransitionStyleCoverVertical 底部弹出
 UIModalTransitionStyleCrossDissolve 淡入
 UIModalTransitionStyleFlipHorizontal 翻转显示
 */
@property (nonatomic,strong) NSNumber * clAuthWindowModalTransitionStyle;

/* UIModalPresentationStyle
 * 若使用窗口模式,请设置为UIModalPresentationOverFullScreen 或不设置
 * iOS13强制全屏,请设置为UIModalPresentationFullScreen
 * UIModalPresentationAutomatic API_AVAILABLE(ios(13.0)) = -2
 * 默认UIModalPresentationFullScreen
 * eg. @(UIModalPresentationOverFullScreen)
 */
/*授权页 ModalPresentationStyle*/
@property (nonatomic,strong) NSNumber * clAuthWindowModalPresentationStyle;
/*协议页 ModalPresentationStyle (授权页使用窗口模式时,协议页强制使用模态弹出)*/
@property (nonatomic,strong) NSNumber * clAppPrivacyWebModalPresentationStyle;

/* UIUserInterfaceStyle
 * UIUserInterfaceStyleUnspecified - 不指定样式,跟随系统设置进行展示
 * UIUserInterfaceStyleLight       - 明亮
 * UIUserInterfaceStyleDark,       - 暗黑 仅对iOS13+系统有效
 */
/*授权页 UIUserInterfaceStyle,默认:UIUserInterfaceStyleLight,eg. @(UIUserInterfaceStyleLight)*/
@property (nonatomic,strong) NSNumber * clAuthWindowOverrideUserInterfaceStyle;

/**
 * 授权页面present弹出时animate动画设置,默认带动画,eg. @(YES)
 */
@property (nonatomic,strong) NSNumber * clAuthWindowPresentingAnimate;

/**弹窗的MaskLayer,用于自定义窗口形状*/
@property (nonatomic,strong) CALayer * clAuthWindowMaskLayer;


//竖屏布局配置对象 -->创建一个布局对象,设置好控件约束属性值,再设置到此属性中
/**竖屏:UIInterfaceOrientationPortrait|UIInterfaceOrientationPortraitUpsideDown
 *eg.   CLUIConfigure * baseUIConfigure = [CLUIConfigure new];
 *      CLOrientationLayOut * clOrientationLayOutPortrait = [CLOrientationLayOut new];
 *      clOrientationLayOutPortrait.clLayoutPhoneCenterY = @(0);
 *      clOrientationLayOutPortrait.clLayoutPhoneLeft = @(50*screenScale);
 *      ...
 *      baseUIConfigure.clOrientationLayOutPortrait = clOrientationLayOutPortrait;
 */
@property (nonatomic,strong) CLOrientationLayOut * clOrientationLayOutPortrait;

//横屏布局配置对象 -->创建一个布局对象,设置好控件约束属性值,再设置到此属性中
/**横屏:UIInterfaceOrientationLandscapeLeft|UIInterfaceOrientationLandscapeRight
 *eg.   CLUIConfigure * baseUIConfigure = [CLUIConfigure new];
 *      CLOrientationLayOut * clOrientationLayOutLandscape = [CLOrientationLayOut new];
 *      clOrientationLayOutLandscape.clLayoutPhoneCenterY = @(0);
 *      clOrientationLayOutLandscape.clLayoutPhoneLeft = @(50*screenScale);
 *      ...
 *      baseUIConfigure.clOrientationLayOutLandscape = clOrientationLayOutLandscape;
 */
@property (nonatomic,strong) CLOrientationLayOut * clOrientationLayOutLandscape;


/**默认界面配置*/
+ (CLUIConfigure *)clDefaultUIConfigure;
@end

/**横竖屏布局配置对象
 配置页面布局相关属性
 */
@interface CLOrientationLayOut : NSObject
/**LOGO图片*/
// 约束均相对vc.view
@property (nonatomic,strong)NSNumber * clLayoutLogoLeft;
@property (nonatomic,strong)NSNumber * clLayoutLogoTop;
@property (nonatomic,strong)NSNumber * clLayoutLogoRight;
@property (nonatomic,strong)NSNumber * clLayoutLogoBottom;
@property (nonatomic,strong)NSNumber * clLayoutLogoWidth;
@property (nonatomic,strong)NSNumber * clLayoutLogoHeight;
@property (nonatomic,strong)NSNumber * clLayoutLogoCenterX;
@property (nonatomic,strong)NSNumber * clLayoutLogoCenterY;

/**手机号显示控件*/
//layout 约束均相对vc.view
@property (nonatomic,strong)NSNumber * clLayoutPhoneLeft;
@property (nonatomic,strong)NSNumber * clLayoutPhoneTop;
@property (nonatomic,strong)NSNumber * clLayoutPhoneRight;
@property (nonatomic,strong)NSNumber * clLayoutPhoneBottom;
@property (nonatomic,strong)NSNumber * clLayoutPhoneWidth;
@property (nonatomic,strong)NSNumber * clLayoutPhoneHeight;
@property (nonatomic,strong)NSNumber * clLayoutPhoneCenterX;
@property (nonatomic,strong)NSNumber * clLayoutPhoneCenterY;

/*一键登录按钮 控件
 注: 一键登录授权按钮 不得隐藏
 **/
//layout 约束均相对vc.view
@property (nonatomic,strong)NSNumber * clLayoutLoginBtnLeft;
@property (nonatomic,strong)NSNumber * clLayoutLoginBtnTop;
@property (nonatomic,strong)NSNumber * clLayoutLoginBtnRight;
@property (nonatomic,strong)NSNumber * clLayoutLoginBtnBottom;
@property (nonatomic,strong)NSNumber * clLayoutLoginBtnWidth;
@property (nonatomic,strong)NSNumber * clLayoutLoginBtnHeight;
@property (nonatomic,strong)NSNumber * clLayoutLoginBtnCenterX;
@property (nonatomic,strong)NSNumber * clLayoutLoginBtnCenterY;

/*隐私条款Privacy
 注: 运营商隐私条款 不得隐藏, 用户条款不限制
 **/
//layout 约束均相对vc.view
@property (nonatomic,strong)NSNumber * clLayoutAppPrivacyLeft;
@property (nonatomic,strong)NSNumber * clLayoutAppPrivacyTop;
@property (nonatomic,strong)NSNumber * clLayoutAppPrivacyRight;
@property (nonatomic,strong)NSNumber * clLayoutAppPrivacyBottom;
@property (nonatomic,strong)NSNumber * clLayoutAppPrivacyWidth;
@property (nonatomic,strong)NSNumber * clLayoutAppPrivacyHeight;
@property (nonatomic,strong)NSNumber * clLayoutAppPrivacyCenterX;
@property (nonatomic,strong)NSNumber * clLayoutAppPrivacyCenterY;

/*Slogan 运营商品牌标签:"认证服务由中国移动/联通/电信提供" label
 注: 运营商品牌标签,不得隐藏
 **/
//layout 约束均相对vc.view
@property (nonatomic,strong)NSNumber * clLayoutSloganLeft;
@property (nonatomic,strong)NSNumber * clLayoutSloganTop;
@property (nonatomic,strong)NSNumber * clLayoutSloganRight;
@property (nonatomic,strong)NSNumber * clLayoutSloganBottom;
@property (nonatomic,strong)NSNumber * clLayoutSloganWidth;
@property (nonatomic,strong)NSNumber * clLayoutSloganHeight;
@property (nonatomic,strong)NSNumber * clLayoutSloganCenterX;
@property (nonatomic,strong)NSNumber * clLayoutSloganCenterY;

/*闪验Slogan 供应商品牌标签:"闪验提供技术支持" label
 **/
//layout 约束均相对vc.view
@property (nonatomic,strong)NSNumber * clLayoutShanYanSloganLeft;
@property (nonatomic,strong)NSNumber * clLayoutShanYanSloganTop;
@property (nonatomic,strong)NSNumber * clLayoutShanYanSloganRight;
@property (nonatomic,strong)NSNumber * clLayoutShanYanSloganBottom;
@property (nonatomic,strong)NSNumber * clLayoutShanYanSloganWidth;
@property (nonatomic,strong)NSNumber * clLayoutShanYanSloganHeight;
@property (nonatomic,strong)NSNumber * clLayoutShanYanSloganCenterX;
@property (nonatomic,strong)NSNumber * clLayoutShanYanSloganCenterY;

/**窗口模式*/
/**窗口中心:CGPoint X Y*/
@property (nonatomic,strong) NSValue * clAuthWindowOrientationCenter;
/**窗口左上角:frame.origin:CGPoint X Y*/
@property (nonatomic,strong) NSValue * clAuthWindowOrientationOrigin;
/**窗口大小:宽 float */
@property (nonatomic,strong) NSNumber * clAuthWindowOrientationWidth;
/**窗口大小:高 float */
@property (nonatomic,strong) NSNumber * clAuthWindowOrientationHeight;

/**默认布局配置
* 用于快速展示默认界面。定制UI时,请重新创建CLOrientationLayOut对象再设置属性,以避免和默认约束冲突
 */
+ (CLOrientationLayOut *)clDefaultOrientationLayOut;

3.横竖屏设置

相关设置属性

/**横竖屏*/
/*是否支持自动旋转 BOOL*/
@property (nonatomic,strong) NSNumber * shouldAutorotate;
/*支持方向 UIInterfaceOrientationMask
 - 如果设置只支持竖屏,只需设置clOrientationLayOutPortrait竖屏布局对象
 - 如果设置只支持横屏,只需设置clOrientationLayOutLandscape横屏布局对象
 - 横竖屏均支持,需同时设置clOrientationLayOutPortrait和clOrientationLayOutLandscape
 */
@property (nonatomic,strong) NSNumber * supportedInterfaceOrientations;
/*默认方向 UIInterfaceOrientation*/
@property (nonatomic,strong) NSNumber * preferredInterfaceOrientationForPresentation;

使用示例代码-请下载demo查看详细配置

#pragma mark - 横竖屏及旋转方向设置
- (CLUIConfigure *)configureStyle3:(CLUIConfigure *)inputConfigure{
    CGFloat screenWidth_Portrait;
    CGFloat screenHeight_Portrait;
    CGFloat screenWidth_Landscape;
    CGFloat screenHeight_Landscape;
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
        screenWidth_Portrait = UIScreen.mainScreen.bounds.size.width;
        screenHeight_Portrait = UIScreen.mainScreen.bounds.size.height;
        screenWidth_Landscape = UIScreen.mainScreen.bounds.size.height;
        screenHeight_Landscape = UIScreen.mainScreen.bounds.size.width;
    }else{
        screenWidth_Portrait = UIScreen.mainScreen.bounds.size.height;
        screenHeight_Portrait = UIScreen.mainScreen.bounds.size.width;
        screenWidth_Landscape = UIScreen.mainScreen.bounds.size.width;
    }
    CLUIConfigure * baseUIConfigure = inputConfigure ? inputConfigure : [CLUIConfigure new];
    baseUIConfigure.viewController = self;
    ...
        
    //layout 布局
    //布局-竖屏
    CLOrientationLayOut * clOrientationLayOutPortrait = [CLOrientationLayOut new];
    
    //窗口中心
    clOrientationLayOutPortrait.clAuthWindowOrientationCenter = [NSValue valueWithCGPoint:CGPointMake(screenWidth_Portrait*0.5, screenHeight_Portrait*0.5)];
    //窗口宽高
    CGFloat authWindowWidth_Portrait = screenWidth_Portrait * 0.8;//窗口宽度为竖屏宽度的0.8
    CGFloat authWindowHeight_Portrait = authWindowWidth_Portrait * 0.8;//窗口高度为窗口宽度的0.8
    clOrientationLayOutPortrait.clAuthWindowOrientationWidth = @(authWindowWidth_Portrait);
    clOrientationLayOutPortrait.clAuthWindowOrientationHeight = @(authWindowHeight_Portrait);
    
    clOrientationLayOutPortrait.clLayoutLogoWidth = @(60*screenScale);
    clOrientationLayOutPortrait.clLayoutLogoHeight = @(60*screenScale);
    clOrientationLayOutPortrait.clLayoutLogoCenterX = @(0);
    clOrientationLayOutPortrait.clLayoutLogoTop = @(25*screenScale);
    
    
    clOrientationLayOutPortrait.clLayoutPhoneCenterY = @(-20*screenScale);
    clOrientationLayOutPortrait.clLayoutPhoneLeft = @(50*screenScale);
    clOrientationLayOutPortrait.clLayoutPhoneRight = @(-50*screenScale);
    clOrientationLayOutPortrait.clLayoutPhoneHeight = @(20*screenScale);
//    clOrientationLayOutPortrait.clLayoutPhoneTop = @(64*screenScale);
    
    clOrientationLayOutPortrait.clLayoutLoginBtnCenterY= @(clOrientationLayOutPortrait.clLayoutPhoneCenterY.floatValue + clOrientationLayOutPortrait.clLayoutPhoneHeight.floatValue*0.5*screenScale + 20*screenScale + 15*screenScale);
    clOrientationLayOutPortrait.clLayoutLoginBtnHeight = @(30*screenScale);
    clOrientationLayOutPortrait.clLayoutLoginBtnLeft = @(70*screenScale);
    clOrientationLayOutPortrait.clLayoutLoginBtnRight = @(-70*screenScale);
    
    clOrientationLayOutPortrait.clLayoutAppPrivacyLeft = @(40*screenScale);
    clOrientationLayOutPortrait.clLayoutAppPrivacyRight = @(-40*screenScale);
    clOrientationLayOutPortrait.clLayoutAppPrivacyBottom = @(0*screenScale);
    clOrientationLayOutPortrait.clLayoutAppPrivacyHeight = @(45*screenScale);
    
    clOrientationLayOutPortrait.clLayoutSloganLeft = @(0);
    clOrientationLayOutPortrait.clLayoutSloganRight = @(0);
    clOrientationLayOutPortrait.clLayoutSloganHeight = @(15*screenScale);
    clOrientationLayOutPortrait.clLayoutSloganBottom = @(clOrientationLayOutPortrait.clLayoutAppPrivacyBottom.floatValue - clOrientationLayOutPortrait.clLayoutAppPrivacyHeight.floatValue);
    
    // 闪验slogan
    clOrientationLayOutPortrait.clLayoutShanYanSloganLeft = @(0);
    clOrientationLayOutPortrait.clLayoutShanYanSloganRight = @(0);
    clOrientationLayOutPortrait.clLayoutShanYanSloganHeight = @(15*screenScale);
    clOrientationLayOutPortrait.clLayoutShanYanSloganBottom = @(clOrientationLayOutPortrait.clLayoutAppPrivacyBottom.floatValue - clOrientationLayOutPortrait.clLayoutAppPrivacyHeight.floatValue-20);
    
    //布局-横屏
    CLOrientationLayOut * clOrientationLayOutLandscape = [CLOrientationLayOut new];
    
    //窗口中心
    clOrientationLayOutLandscape.clAuthWindowOrientationCenter = [NSValue valueWithCGPoint:CGPointMake(screenWidth_Landscape*0.5, screenHeight_Landscape*0.5)];
    //窗口宽高
    CGFloat authWindowWidth_Landscape = screenWidth_Portrait * 0.8;//窗口宽度为竖屏宽度的0.8
    CGFloat authWindowHeight_Landscape = authWindowWidth_Landscape * 0.8;//窗口高度为窗口宽度的0.8
    clOrientationLayOutLandscape.clAuthWindowOrientationWidth = @(authWindowWidth_Landscape);
    clOrientationLayOutLandscape.clAuthWindowOrientationHeight = @(authWindowHeight_Landscape);
    
    clOrientationLayOutLandscape.clLayoutLogoWidth = @(60*screenScale);
    clOrientationLayOutLandscape.clLayoutLogoHeight = @(60*screenScale);
    clOrientationLayOutLandscape.clLayoutLogoCenterX = @(0);
    clOrientationLayOutLandscape.clLayoutLogoTop = @(25*screenScale);
    
    clOrientationLayOutLandscape.clLayoutPhoneCenterY = @(-20*screenScale);
    clOrientationLayOutLandscape.clLayoutPhoneLeft = @(50*screenScale);
    clOrientationLayOutLandscape.clLayoutPhoneRight = @(-50*screenScale);
    clOrientationLayOutLandscape.clLayoutPhoneHeight = @(20*screenScale);
    
    clOrientationLayOutLandscape.clLayoutLoginBtnCenterY= @(clOrientationLayOutLandscape.clLayoutPhoneCenterY.floatValue + clOrientationLayOutLandscape.clLayoutPhoneHeight.floatValue*0.5*screenScale + 20*screenScale + 15*screenScale);
    clOrientationLayOutLandscape.clLayoutLoginBtnHeight = @(30*screenScale);
    clOrientationLayOutLandscape.clLayoutLoginBtnLeft = @(70*screenScale);
    clOrientationLayOutLandscape.clLayoutLoginBtnRight = @(-70*screenScale);
    
    clOrientationLayOutLandscape.clLayoutAppPrivacyLeft = @(40*screenScale);
    clOrientationLayOutLandscape.clLayoutAppPrivacyRight = @(-40*screenScale);
    clOrientationLayOutLandscape.clLayoutAppPrivacyBottom = @(0*screenScale);
    clOrientationLayOutLandscape.clLayoutAppPrivacyHeight = @(45*screenScale);
    
    clOrientationLayOutLandscape.clLayoutSloganLeft = @(0);
    clOrientationLayOutLandscape.clLayoutSloganRight = @(0);
    clOrientationLayOutLandscape.clLayoutSloganHeight = @(15*screenScale);
    clOrientationLayOutLandscape.clLayoutSloganBottom = @(clOrientationLayOutLandscape.clLayoutAppPrivacyBottom.floatValue - clOrientationLayOutLandscape.clLayoutAppPrivacyHeight.floatValue);
    
    
    clOrientationLayOutLandscape.clLayoutShanYanSloganLeft = @(0);
    clOrientationLayOutLandscape.clLayoutShanYanSloganRight = @(0);
    clOrientationLayOutLandscape.clLayoutShanYanSloganHeight = @(15*screenScale);
    clOrientationLayOutLandscape.clLayoutShanYanSloganBottom = @(clOrientationLayOutLandscape.clLayoutAppPrivacyBottom.floatValue - clOrientationLayOutLandscape.clLayoutAppPrivacyHeight.floatValue-20);
    
    baseUIConfigure.clOrientationLayOutPortrait = clOrientationLayOutPortrait;
    baseUIConfigure.clOrientationLayOutLandscape = clOrientationLayOutLandscape;
    return baseUIConfigure;
}

4.弹窗模式设置

4.1 相关设置属性

/**以窗口方式显示授权页
 */
/**以窗口方式显示 BOOL, default is NO */
@property (nonatomic,strong) NSNumber * clAuthTypeUseWindow;
/**窗口圆角 float*/
@property (nonatomic,strong) NSNumber * clAuthWindowCornerRadius;

/**clAuthWindowModalTransitionStyle系统自带的弹出方式 仅支持以下三种
 UIModalTransitionStyleCoverVertical 底部弹出
 UIModalTransitionStyleCrossDissolve 淡入
 UIModalTransitionStyleFlipHorizontal 翻转显示
 */
@property (nonatomic,strong) NSNumber * clAuthWindowModalTransitionStyle;

/**弹窗的MaskLayer,用于自定义窗口形状*/
@property (nonatomic,strong) CALayer * clAuthWindowMaskLayer;

4.2 布局示例代码
详细请下载demo查看配置

#pragma mark - 样式3:窗口样式
- (CLUIConfigure *)configureStyle3:(CLUIConfigure *)inputConfigure{
    CGFloat screenWidth_Portrait;
    CGFloat screenHeight_Portrait;
    CGFloat screenWidth_Landscape;
    CGFloat screenHeight_Landscape;
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
        screenWidth_Portrait = UIScreen.mainScreen.bounds.size.width;
        screenHeight_Portrait = UIScreen.mainScreen.bounds.size.height;
        screenWidth_Landscape = UIScreen.mainScreen.bounds.size.height;
        screenHeight_Landscape = UIScreen.mainScreen.bounds.size.width;
    }else{
        screenWidth_Portrait = UIScreen.mainScreen.bounds.size.height;
        screenHeight_Portrait = UIScreen.mainScreen.bounds.size.width;
        screenWidth_Landscape = UIScreen.mainScreen.bounds.size.width;
        screenHeight_Landscape = UIScreen.mainScreen.bounds.size.height;
    }
    
        CGFloat screenScale = [UIScreen mainScreen].bounds.size.width/375.0;
    if (screenScale > 1) {
        screenScale = 1;
    }
    
    CLUIConfigure * baseUIConfigure = inputConfigure;
    
    baseUIConfigure.clCheckBoxValue = @(YES);
    
    //横竖屏旋转方向设置
    baseUIConfigure.shouldAutorotate = @(YES);
    baseUIConfigure.supportedInterfaceOrientations = @(UIInterfaceOrientationMaskAll);
	//baseUIConfigure.preferredInterfaceOrientationForPresentation = @(UIInterfaceOrientationLandscapeLeft);
    
    //使用窗口方式
    baseUIConfigure.clAuthTypeUseWindow = @(YES);
    baseUIConfigure.clAuthWindowCornerRadius = @(20);
    baseUIConfigure.clAuthWindowModalTransitionStyle = @(UIModalTransitionStyleCoverVertical);
    
    /****页面元素配置****/
    baseUIConfigure.clBackgroundImg = [UIImage imageNamed:@"eb9a0dae18491990a43fe02832d3cafa"];
    baseUIConfigure.clNavigationBackgroundClear = @(YES);
    baseUIConfigure.clNavigationBackBtnHidden = @(YES);
    baseUIConfigure.clNavigationBottomLineHidden = @(YES);
    // 自定义协议加载
    baseUIConfigure.clAppPrivacyFirst = @[@"闪验测试连接1",[NSURL URLWithString:@"https://baidu.com"]];
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"ShanYanIndex" ofType:@"html"];
    //baseUIConfigure.clAppPrivacySecond = @[@"闪验测试连接2",[NSURL URLWithString:@"https://sina.com"]];
	baseUIConfigure.clAppPrivacySecond = @[@"本地协议地址",[NSURL fileURLWithPath:filePath]];
    
    ...
        
    /****横竖屏布局配置****/   
    
    //布局-竖屏
    CLOrientationLayOut * clOrientationLayOutPortrait = [CLOrientationLayOut new];
    
    //窗口中心
    clOrientationLayOutPortrait.clAuthWindowOrientationCenter = [NSValue valueWithCGPoint:CGPointMake(screenWidth_Portrait*0.5, screenHeight_Portrait*0.5)];
    //窗口宽高
    CGFloat authWindowWidth_Portrait = screenWidth_Portrait * 0.8;//窗口宽度为竖屏宽度的0.8
    CGFloat authWindowHeight_Portrait = authWindowWidth_Portrait * 0.8;//窗口高度为窗口宽度的0.8
    clOrientationLayOutPortrait.clAuthWindowOrientationWidth = @(authWindowWidth_Portrait);
    clOrientationLayOutPortrait.clAuthWindowOrientationHeight = @(authWindowHeight_Portrait);
    
    clOrientationLayOutPortrait.clLayoutLogoWidth = @(60*screenScale);
    clOrientationLayOutPortrait.clLayoutLogoHeight = @(60*screenScale);
    clOrientationLayOutPortrait.clLayoutLogoCenterX = @(0);
    clOrientationLayOutPortrait.clLayoutLogoTop = @(25*screenScale);
    
    clOrientationLayOutPortrait.clLayoutPhoneCenterY = @(-20*screenScale);
    clOrientationLayOutPortrait.clLayoutPhoneLeft = @(50*screenScale);
    clOrientationLayOutPortrait.clLayoutPhoneRight = @(-50*screenScale);
    clOrientationLayOutPortrait.clLayoutPhoneHeight = @(20*screenScale);
    
    clOrientationLayOutPortrait.clLayoutLoginBtnCenterY= @(clOrientationLayOutPortrait.clLayoutPhoneCenterY.floatValue + clOrientationLayOutPortrait.clLayoutPhoneHeight.floatValue*0.5*screenScale + 20*screenScale + 15*screenScale);
    clOrientationLayOutPortrait.clLayoutLoginBtnHeight = @(30*screenScale);
    clOrientationLayOutPortrait.clLayoutLoginBtnLeft = @(70*screenScale);
    clOrientationLayOutPortrait.clLayoutLoginBtnRight = @(-70*screenScale);
    
    clOrientationLayOutPortrait.clLayoutAppPrivacyLeft = @(40*screenScale);
    clOrientationLayOutPortrait.clLayoutAppPrivacyRight = @(-40*screenScale);
    clOrientationLayOutPortrait.clLayoutAppPrivacyBottom = @(0*screenScale);
    clOrientationLayOutPortrait.clLayoutAppPrivacyHeight = @(45*screenScale);
    
    clOrientationLayOutPortrait.clLayoutSloganLeft = @(0);
    clOrientationLayOutPortrait.clLayoutSloganRight = @(0);
    clOrientationLayOutPortrait.clLayoutSloganHeight = @(15*screenScale);
    clOrientationLayOutPortrait.clLayoutSloganBottom = @(clOrientationLayOutPortrait.clLayoutAppPrivacyBottom.floatValue - clOrientationLayOutPortrait.clLayoutAppPrivacyHeight.floatValue);
    
    //布局-横屏
    CLOrientationLayOut * clOrientationLayOutLandscape = [CLOrientationLayOut new];
    
    //窗口中心
    clOrientationLayOutLandscape.clAuthWindowOrientationCenter = [NSValue valueWithCGPoint:CGPointMake(screenWidth_Landscape*0.5, screenHeight_Landscape*0.5)];
    //窗口宽高
    CGFloat authWindowWidth_Landscape = screenWidth_Portrait * 0.8;//窗口宽度为竖屏宽度的0.8
    CGFloat authWindowHeight_Landscape = authWindowWidth_Landscape * 0.8;//窗口高度为窗口宽度的0.8
    clOrientationLayOutLandscape.clAuthWindowOrientationWidth = @(authWindowWidth_Landscape);
    clOrientationLayOutLandscape.clAuthWindowOrientationHeight = @(authWindowHeight_Landscape);
    
    clOrientationLayOutLandscape.clLayoutLogoWidth = @(60*screenScale);
    clOrientationLayOutLandscape.clLayoutLogoHeight = @(60*screenScale);
    clOrientationLayOutLandscape.clLayoutLogoCenterX = @(0);
    clOrientationLayOutLandscape.clLayoutLogoTop = @(25*screenScale);
    
    clOrientationLayOutLandscape.clLayoutPhoneCenterY = @(-20*screenScale);
    clOrientationLayOutLandscape.clLayoutPhoneLeft = @(50*screenScale);
    clOrientationLayOutLandscape.clLayoutPhoneRight = @(-50*screenScale);
    clOrientationLayOutLandscape.clLayoutPhoneHeight = @(20*screenScale);
    
    clOrientationLayOutLandscape.clLayoutLoginBtnCenterY= @(clOrientationLayOutLandscape.clLayoutPhoneCenterY.floatValue + clOrientationLayOutLandscape.clLayoutPhoneHeight.floatValue*0.5*screenScale + 20*screenScale + 15*screenScale);
    clOrientationLayOutLandscape.clLayoutLoginBtnHeight = @(30*screenScale);
    clOrientationLayOutLandscape.clLayoutLoginBtnLeft = @(70*screenScale);
    clOrientationLayOutLandscape.clLayoutLoginBtnRight = @(-70*screenScale);
    
    clOrientationLayOutLandscape.clLayoutAppPrivacyLeft = @(40*screenScale);
    clOrientationLayOutLandscape.clLayoutAppPrivacyRight = @(-40*screenScale);
    clOrientationLayOutLandscape.clLayoutAppPrivacyBottom = @(0*screenScale);
    clOrientationLayOutLandscape.clLayoutAppPrivacyHeight = @(45*screenScale);
    
    clOrientationLayOutLandscape.clLayoutSloganLeft = @(0);
    clOrientationLayOutLandscape.clLayoutSloganRight = @(0);
    clOrientationLayOutLandscape.clLayoutSloganHeight = @(15*screenScale);
    clOrientationLayOutLandscape.clLayoutSloganBottom = @(clOrientationLayOutLandscape.clLayoutAppPrivacyBottom.floatValue - clOrientationLayOutLandscape.clLayoutAppPrivacyHeight.floatValue);
    
    baseUIConfigure.clOrientationLayOutPortrait = clOrientationLayOutPortrait;
    baseUIConfigure.clOrientationLayOutLandscape = clOrientationLayOutLandscape;
    
    return baseUIConfigure;
}

4.3 添加弹窗背景蒙版
实现思路:以弹窗模式弹出,窗口大小设为全屏,将窗口背景设为蒙版色,再自定义一个授权页窗口背景view充当授权窗口,将控件放在窗口背景view中

添加蒙版-示例代码(请参考demo中OC示例代码)

//弹窗+背景蒙版
//实现思路:以弹窗模式弹出,窗口大小设为全屏,将窗口背景设为蒙版色,再自定义一个授权页窗口背景view充当授权窗口,将控件放在窗口背景view中
+(CLUIConfigure*)shanYanUIConfigureMakerStyle2{
    
    
    UIColor * light_foreground = [UIColor colorWithRed:0.451 green:0.486 blue:1.000 alpha:1];
    UIColor * dark_foreground = [UIColor colorWithRed:0.773 green:0.792 blue:1.000 alpha:1];

    UIColor * light_background = [UIColor colorWithRed:0.651 green:0.679 blue:0.809 alpha:1];
    UIColor * dark_background = [UIColor colorWithRed:0.146 green:0.140 blue:0.307 alpha:1];
    
    CLUIConfigure * baseUIConfigure = [[CLUIConfigure alloc]init];
    
    baseUIConfigure.manualDismiss = @(YES);
    
    baseUIConfigure.shouldAutorotate = @(NO);
    baseUIConfigure.supportedInterfaceOrientations =@(UIInterfaceOrientationMaskPortrait);;
    
//    baseUIConfigure.clAuthWindowModalPresentationStyle = @(UIModalPresentationCustom);
    baseUIConfigure.clAuthWindowModalTransitionStyle = @(UIModalTransitionStyleCrossDissolve);
//    baseUIConfigure.clAuthWindowPresentingAnimate = @(YES);

    baseUIConfigure.clAuthTypeUseWindow = @(YES);

    if (@available(iOS 12.0, *)) {
        baseUIConfigure.clAuthWindowOverrideUserInterfaceStyle = @(UIUserInterfaceStyleUnspecified);
    }
    
    baseUIConfigure.clNavigationBarHidden = @(YES);

    baseUIConfigure.clPrefersStatusBarHidden = @(YES);
    
    baseUIConfigure.clLogoImage = [UIImage imageNamed:@"shanyanLogo1"];
    baseUIConfigure.clLogoCornerRadius = @(10);
    
    baseUIConfigure.clPhoneNumberColor = randomDymcialColor;
    baseUIConfigure.clPhoneNumberFont = [UIFont boldSystemFontOfSize:20];
    baseUIConfigure.clPhoneNumberTextAlignment = @(NSTextAlignmentCenter);
    
//    baseUIConfigure.clAppPrivacyWebAttributesTitle = [[NSAttributedString alloc]initWithString:@"闪验运营商协议测试文字" attributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSize:14],NSForegroundColorAttributeName:[UIColor generateDynamicColor:UIColor.flatLimeColor darkColor:UIColor.flatGreenColorDark]}];
    
    baseUIConfigure.clAppPrivacyColor = @[randomDymcialColor,randomDymcialColor];
    baseUIConfigure.clAppPrivacyTextFont = [UIFont boldSystemFontOfSize:12];
    baseUIConfigure.clAppPrivacyTextAlignment =  @(NSTextAlignmentLeft);
    baseUIConfigure.clAppPrivacyPunctuationMarks = @(YES);
//    baseUIConfigure.clAppPrivacyLineSpacing = @(5);
//    baseUIConfigure.clAppPrivacyNeedSizeToFit = @(YES);
    //失效
    baseUIConfigure.clAppPrivacyTextContainerInset = [NSValue valueWithUIEdgeInsets:UIEdgeInsetsMake(20, 35, 0, 15)];
    baseUIConfigure.clAppPrivacyAbbreviatedName = @"🐶app";
       
    baseUIConfigure.clAppPrivacyFirst = @[@"用户协议1",[NSURL URLWithString:@"https://m.baidu.com"]];
    baseUIConfigure.clAppPrivacySecond = @[@"用户协议2",@"https://m.toutiao.com"];
    baseUIConfigure.clAppPrivacyThird = @[@"用户协议3",[[NSBundle mainBundle] pathForResource:@"ShanYanIndex" ofType:@"html"]];
    baseUIConfigure.clPrivacyShowUnderline = @(YES);
    
    baseUIConfigure.clLoginBtnBorderWidth = @(2);
    baseUIConfigure.clLoginBtnCornerRadius = @(5);
    

    baseUIConfigure.clSloganTextFont = [UIFont boldSystemFontOfSize:12];
    baseUIConfigure.clSloganTextColor = randomDymcialColor;
    baseUIConfigure.clSlogaTextAlignment = @(NSTextAlignmentCenter);
    
    baseUIConfigure.clCheckBoxValue = @(NO);
    baseUIConfigure.clCheckBoxSize = [NSValue valueWithCGSize:CGSizeMake(40, 40)];
 
    
    CGFloat screenWidth_Portrait;
    CGFloat screenHeight_Portrait;
    CGFloat screenWidth_Landscape;
    CGFloat screenHeight_Landscape;
    UIInterfaceOrientation orientation = UIApplication.sharedApplication.statusBarOrientation;
    if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown){
        screenWidth_Portrait = UIScreen.mainScreen.bounds.size.width;
        screenHeight_Portrait = UIScreen.mainScreen.bounds.size.height;
        screenWidth_Landscape = UIScreen.mainScreen.bounds.size.height;
        screenHeight_Landscape = UIScreen.mainScreen.bounds.size.width;
    }else{
        screenWidth_Portrait = UIScreen.mainScreen.bounds.size.height;
        screenHeight_Portrait = UIScreen.mainScreen.bounds.size.width;
        screenWidth_Landscape = UIScreen.mainScreen.bounds.size.height;
        screenHeight_Landscape = UIScreen.mainScreen.bounds.size.width;
    }
    
    //添加授权页自定义控件
    UIButton * custom0 = [[UIButton alloc]init];
    custom0.layer.cornerRadius = 10;
    custom0.titleLabel.font = [UIFont boldSystemFontOfSize:13];
    [custom0 setTitle:@"自定义按钮0" forState:(UIControlStateNormal)];
    [custom0 addTarget:self action:@selector(customButton0Click:) forControlEvents:UIControlEventTouchUpInside];
    [custom0 setTitleColor:randomDymcialColor forState:(UIControlStateNormal)];
    custom0.backgroundColor = randomDymcialColor;
    
    UIButton * custom1 = [[UIButton alloc]init];
    custom1.layer.cornerRadius = 10;
    custom1.titleLabel.font = [UIFont boldSystemFontOfSize:13];
    [custom1 setTitle:@"自定义按钮1" forState:(UIControlStateNormal)];
    [custom1 addTarget:self action:@selector(customButton1Click:) forControlEvents:UIControlEventTouchUpInside];
    [custom1 setTitleColor:randomDymcialColor forState:(UIControlStateNormal)];
    custom1.backgroundColor = randomDymcialColor;

    UIImageView * custom_img_0 = [[UIImageView alloc]init];
    UIImageView * custom_img_1 = [[UIImageView alloc]init];
    UIImageView * custom_img_2 = [[UIImageView alloc]init];
    custom_img_0.layer.cornerRadius = 10;
    custom_img_1.layer.cornerRadius = 10;
    custom_img_2.layer.cornerRadius = 10;
    custom_img_0.image = [UIImage imageNamed:@"电信"];
    custom_img_1.image = [UIImage imageNamed:@"移动"];
    custom_img_2.image = [UIImage imageNamed:@"联通"];
    
    
    baseUIConfigure.customAreaView = ^(UIView * _Nonnull customAreaView) {
       
        customAreaView.backgroundColor = [UIColor colorWithWhite:0.5 alpha:0.2];
        
        //白色圆角背景
        UIImageView * whiteBGView = [[UIImageView alloc]init];
        whiteBGView.userInteractionEnabled = YES;
        whiteBGView.image = [UIImage imageNamed:@"eb9a0dae18491990a43fe02832d3cafa"];
        
        whiteBGView.layer.shadowColor = UIColor.grayColor.CGColor;
        whiteBGView.layer.shadowOpacity = 9;
        whiteBGView.layer.shadowRadius = 30;
        whiteBGView.layer.shadowOffset = CGSizeMake(5, 5);
//        whiteBGView.layer.masksToBounds = YES;
        [customAreaView addSubview:whiteBGView];
        [whiteBGView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.centerX.centerY.mas_equalTo(0);
            make.height.mas_equalTo(screenHeight_Portrait*0.5);
            make.width.mas_equalTo(screenWidth_Portrait*0.75);
        }];
        
        UIButton * close = [[UIButton alloc]init];
        [close addTarget:self action:@selector(customButton1Click:) forControlEvents:(UIControlEventTouchUpInside)];
        close.imageEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10);
        [close setImage:[UIImage imageNamed:@"close"] forState:(UIControlStateNormal)];
        close.layer.cornerRadius = 20;
        close.layer.masksToBounds = YES;
        [customAreaView addSubview:close];
        [close mas_makeConstraints:^(MASConstraintMaker *make) {
            make.centerX.mas_equalTo(whiteBGView.mas_right);
            make.bottom.mas_equalTo(whiteBGView.mas_top);
            make.width.height.mas_equalTo(50);
        }];
    
        [whiteBGView addSubview:custom0];
        [custom0 mas_makeConstraints:^(MASConstraintMaker *make) {
            make.centerX.mas_equalTo(-50);
            make.width.mas_equalTo(80);
            make.height.mas_equalTo(30);
            make.centerY.mas_equalTo(40);
        }];
        
        [whiteBGView addSubview:custom1];
        [custom1 mas_makeConstraints:^(MASConstraintMaker *make) {
            make.centerX.mas_equalTo(50);
            make.width.mas_equalTo(80);
            make.height.mas_equalTo(30);
            make.centerY.mas_equalTo(40);
        }];
        
        [whiteBGView addSubview:custom_img_0];
        [customAreaView addSubview:custom_img_1];
        [customAreaView addSubview:custom_img_2];

        [custom_img_1 mas_makeConstraints:^(MASConstraintMaker *make) {
            make.centerX.mas_equalTo(0);
            make.width.height.mas_equalTo(30);
            make.top.mas_equalTo(custom1.mas_bottom).offset(20);
        }];
        [custom_img_0 mas_makeConstraints:^(MASConstraintMaker *make) {
            make.width.height.centerY.mas_equalTo(custom_img_1);
            make.right.mas_equalTo(custom_img_1.mas_left).offset(-30);
        }];
        [custom_img_2 mas_makeConstraints:^(MASConstraintMaker *make) {
             make.width.height.centerY.mas_equalTo(custom_img_1);
             make.left.mas_equalTo(custom_img_1.mas_right).offset(30);
        }];
    };
        
    CLOrientationLayOut * layOutPortrait = [[CLOrientationLayOut alloc]init];
    
    layOutPortrait.clAuthWindowOrientationCenter = [NSValue valueWithCGPoint:CGPointMake(screenWidth_Portrait*0.5, screenHeight_Portrait*0.5)];
    layOutPortrait.clAuthWindowOrientationWidth = @(screenWidth_Portrait);
    layOutPortrait.clAuthWindowOrientationHeight = @(screenHeight_Portrait);
    
    layOutPortrait.clLayoutLogoCenterX = @(0);
    layOutPortrait.clLayoutLogoTop = @(screenHeight_Portrait*0.25 + 60);
    layOutPortrait.clLayoutLogoWidth = @(100);
    layOutPortrait.clLayoutLogoHeight = @(50);
    
    layOutPortrait.clLayoutPhoneCenterX = @(0);
    layOutPortrait.clLayoutPhoneTop = @(layOutPortrait.clLayoutLogoTop.floatValue + layOutPortrait.clLayoutLogoHeight.floatValue + 10);
    layOutPortrait.clLayoutPhoneWidth = @(screenWidth_Portrait);
    layOutPortrait.clLayoutPhoneHeight = @(40);

    layOutPortrait.clLayoutLoginBtnCenterX = @(0);
    layOutPortrait.clLayoutLoginBtnWidth = @(150);
    layOutPortrait.clLayoutLoginBtnTop = @(layOutPortrait.clLayoutPhoneTop.floatValue + layOutPortrait.clLayoutPhoneHeight.floatValue + 20);
    layOutPortrait.clLayoutLoginBtnHeight = @(45);
    
    
    layOutPortrait.clLayoutShanYanSloganBottom = @(-screenHeight_Portrait*0.25 -20);
    layOutPortrait.clLayoutShanYanSloganLeft = @(0);
    layOutPortrait.clLayoutShanYanSloganRight = @(0);
    layOutPortrait.clLayoutShanYanSloganHeight = @(20);

    layOutPortrait.clLayoutSloganBottom = @(layOutPortrait.clLayoutShanYanSloganBottom.floatValue - layOutPortrait.clLayoutShanYanSloganHeight.floatValue);
    layOutPortrait.clLayoutSloganLeft = @(0);
    layOutPortrait.clLayoutSloganRight = @(0);
    layOutPortrait.clLayoutSloganHeight = @(20);
    
    layOutPortrait.clLayoutAppPrivacyLeft = @(screenWidth_Portrait*0.125 + 50);
    layOutPortrait.clLayoutAppPrivacyRight = @(-screenWidth_Portrait*0.125 -30);
    layOutPortrait.clLayoutAppPrivacyBottom = @(layOutPortrait.clLayoutSloganBottom.floatValue - layOutPortrait.clLayoutSloganHeight.floatValue);
    layOutPortrait.clLayoutAppPrivacyHeight = @(50);


    baseUIConfigure.clOrientationLayOutPortrait = layOutPortrait;
    
    return baseUIConfigure;
}

5.添加自定义控件示例

ObjC:

// 快捷登录
- (void)quickLoginBtnClick:(UIButton *)sender {
    ...    

    CLUIConfigure * baseUIConfigure = [CLUIConfigure new];
    baseUIConfigure.viewController = self;
    CGFloat screenScale = [UIScreen mainScreen].bounds.size.width/375.0;
    baseUIConfigure.customAreaView = ^(UIView * _Nonnull customAreaView) {

        UIButton * button = [[UIButton alloc]init];
        [button setTitle:@"其他方式登录" forState:(UIControlStateNormal)];
        button.titleLabel.font = [UIFont systemFontOfSize:14];
        [button setTitleColor:[UIColor grayColor] forState:(UIControlStateNormal)];
        [button addTarget:self action:@selector(otherLoginWayBtnCliced:) forControlEvents:(UIControlEventTouchUpInside)];
        [customAreaView addSubview:button];

        [button mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.right.mas_equalTo(0);
            make.top.mas_equalTo(280*screenScale);
            make.height.mas_equalTo(40);
        }];
    };  
    ...
}
//授权页 点击自定义控件绑定的方法
-(void)otherLoginWayBtnCliced:(UIButton *)sender{
	//关闭页面
    [CLShanYanSDKManager finishAuthControllerCompletion:^{
       //如需关闭后present/push新页面,建议在completion回调中执行 
    }];
}

Swift:

@IBAction func quickLogin(_ sender: UIButton) {
      ...

      let baseUIConfigure = CLUIConfigure()
      //requried
      baseUIConfigure.viewController = self
      //Optional:
      let screenScale = UIScreen.main.bounds.size.width/375.0;
      baseUIConfigure.customAreaView = {
          [unowned self] view in
          let otherLoginButtonWay = UIButton()
          otherLoginButtonWay.setTitle("其他方式登录", for: .normal)
          otherLoginButtonWay.setTitleColor(UIColor.gray, for: .normal)
          otherLoginButtonWay.titleLabel?.font = UIFont.systemFont(ofSize: 15)
          view.addSubview(otherLoginButtonWay)
          otherLoginButtonWay.snp.makeConstraints { (make) in
              make.centerX.equalToSuperview()
              make.top.equalTo(280*screenScale)
              make.width.equalToSuperview()
              make.height.equalTo(40)
          }
          otherLoginButtonWay.addTarget(self, action: #selector(self.otherLoginButtonWay(_:)), for: .touchUpInside)
      }
      ...
  }

//授权页 点击其他方式登录
@objc func otherLoginButtonWay(_ sender: UIButton) {
    DispatchQueue.main.async(execute: {
        HUD.showSuccess(withStatus: ("用户选择其他方式登录"))
    })
}

6.添加自定义loading

    // 自定义loading--将loadingView添加到containerView上进行显示
    baseUIConfigure.loadingView = ^(UIView * _Nonnull containerView) {
        UIImage *image = [YYImage imageNamed:@"KungFuPanda.gif"];
        UIImageView *imageBackground = [[YYAnimatedImageView alloc] initWithImage:image];
        [containerView addSubview:imageBackground];
        
        [imageBackground mas_makeConstraints:^(MASConstraintMaker *make) {
            make.size.mas_equalTo(CGSizeMake(80, 80));
            make.center.mas_equalTo(0);
        }];
        
        imageBackground.layer.cornerRadius = 40;
        imageBackground.layer.masksToBounds = YES;
    };

7.自定义设置隐私协议弹窗

...
baseUIConfigure.customPrivacyAlertView = ^(UIViewController * _Nonnull authPageVC) {
    UIAlertController * privacyAlert = [UIAlertController alertControllerWithTitle:@"用户注册及使用APP隐私协议" message:@"在此特别提醒您(用户)在注册成为用户之前,请认真阅读本《用户协议》(以下简称“协议”),确保您充分理解本协议中各条款。请您审慎阅读并选择接受或不接受本协议。您的注册、登录、使用等行为将视为对本协议的接受,并同意接受本协议各项条款的约束。本协议约定南京喵星科技有限公司(以下简称“喵星”)与用户之间关于“喵小瞳”软件服务(以下简称“服务“)的权利义务。“用户”是指注册、登录、使用本服务的个人。本协议可由喵星随时更新,更新后的协议条款一旦公布即代替原来的协议条款,恕不再另行通知,用户可在本APP中查阅最新版协议条款。在修改协议条款后,如果用户不接受修改后的条款,请立即停止使用喵小瞳提供的服务,用户继续使用服务将被视为接受修改后的协议。 " preferredStyle:(UIAlertControllerStyleAlert)];
    [privacyAlert addAction:[UIAlertAction actionWithTitle:@"拒绝" style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {
        @strongify(self)
        [self hideShanYanAuthPageMaskViewWhenUseWindow];
        [CLShanYanSDKManager finishAuthControllerCompletion:nil];
    }]];
    [privacyAlert addAction:[UIAlertAction actionWithTitle:@"同意" style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
        //通知sdk勾选协议
        [CLShanYanSDKManager setCheckBoxValue:YES];
    }]];
    [authPageVC presentViewController:privacyAlert animated:YES completion:nil];
};
...

8.适配iOS13

弹出风格

/* UIModalPresentationStyle
 * 若使用窗口模式,请设置为UIModalPresentationOverFullScreen 或不设置
 * iOS13强制全屏,请设置为UIModalPresentationFullScreen
 * UIModalPresentationAutomatic API_AVAILABLE(ios(13.0)) = -2
 * eg. @(UIModalPresentationOverFullScreen)
 */
@property (nonatomic,strong) NSNumber * clAuthWindowModalPresentationStyle;

状态栏

/*状态栏样式
 *Info.plist: View controller-based status bar appearance = YES
 *
 *UIStatusBarStyleDefault:状态栏显示 黑
 *UIStatusBarStyleLightContent:状态栏显示 白
 *UIStatusBarStyleDarkContent:状态栏显示 黑 API_AVAILABLE(ios(13.0)) = 3
 **eg. @(UIStatusBarStyleLightContent)
 */
@property (nonatomic,strong)NSNumber * clPreferredStatusBarStyle;

暗黑模式

/* UIUserInterfaceStyle
 * UIUserInterfaceStyleUnspecified - 不指定样式,跟随系统设置进行展示
 * UIUserInterfaceStyleLight       - 明亮
 * UIUserInterfaceStyleDark,       - 暗黑 仅对iOS13+系统有效
 */
/*授权页 UIUserInterfaceStyle,默认:UIUserInterfaceStyleLight,eg. @(UIUserInterfaceStyleLight)*/
@property (nonatomic,strong) NSNumber * clAuthWindowOverrideUserInterfaceStyle;

**

+(UIColor *)generateDynamicColor:(UIColor *)lightModeColor darkModeColor:(UIColor *)darkModeColor {
    
    if (@available(iOS 13.0, *)) {
        return [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
            if (traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
                return darkModeColor;
            } else {
                return lightModeColor;
            }
        }];
    }
    
    return lightModeColor;
}

授权页面暗黑模式颜色适配
注:需先设置页面跟随系统模式显示

- (void)sy_login{
    
    CLUIConfigure *cfg = [CLUIConfigure clDefaultUIConfigure];
    cfg.viewController = self;
    cfg.clOrientationLayOutPortrait = [CLOrientationLayOut clDefaultOrientationLayOut];
    
    // 开启跟随系统显示模式
    if (@available(iOS 12.0, *)) {
        cfg.clAuthWindowOverrideUserInterfaceStyle = @(UIUserInterfaceStyleUnspecified);
    } else {
        // Fallback on earlier versions
    }
    
    // 动态适配图片显示
    cfg.clLogoImage = [UIImage imageNamed:@"apple_icon"];
	
    // 动态适配背景色、文字颜色
    cfg.clLoginBtnBgColor = [UIColorTools generateDynamicColor:UIColor.blackColor darkModeColor:UIColor.redColor];
    cfg.clLoginBtnTextColor = [UIColorTools generateDynamicColor:UIColor.whiteColor darkModeColor:UIColor.yellowColor];
    cfg.customAreaView = ^(UIView * _Nonnull customAreaView) {
        // 授权页面背景色动态配置
        customAreaView.backgroundColor = [UIColorTools generateDynamicColor:UIColor.whiteColor darkModeColor:UIColor.brownColor];
    };

    // 拉起授权页面
    [CLShanYanSDKManager quickAuthLoginWithConfigure:cfg openLoginAuthListener:^(CLCompleteResult * _Nonnull completeResult) {
        
    } oneKeyLoginListener:^(CLCompleteResult * _Nonnull completeResult) {
        
    }];
}

授权页面暗黑模式图片适配
图片适配需要提供两套相同名字的图片,分别对应any-dark位置,如下图所示;
注意:
1.图片为同名,如"apple_icon@2x.png"(两张图片名称设置成一样),设置后图片会根据当前显示模式自动适配
2.右侧Appearances 需设置成“Any,Dark”模式
适配图.png
图片适配示例代码

cfg.clLogoImage = [UIImage imageNamed:@"apple_icon"];

效果展示视屏
点击查看【bilibili】


9.CheckBox勾选框位置调整

可调整属性

/**协议勾选框 尺寸 NSValue->CGSize eg.[NSValue valueWithCGSize:CGSizeMake(25, 25)]*/
@property (nonatomic,strong) NSValue *clCheckBoxSize;
/**协议勾选框 UIButton.image图片缩进 UIEdgeInset eg.[NSValue valueWithUIEdgeInsets:UIEdgeInsetsMake(2, 2, 2, 2)]*/
@property (nonatomic,strong) NSValue *clCheckBoxImageEdgeInsets;
/**协议勾选框 设置CheckBox顶部与隐私协议控件顶部对齐 YES或大于0生效 eg.@(YES)*/
@property (nonatomic,strong) NSNumber *clCheckBoxVerticalAlignmentToAppPrivacyTop;
/**协议勾选框 设置CheckBox顶部与隐私协议控件竖向中心对齐 YES或大于0生效 eg.@(YES)*/
@property (nonatomic,strong) NSNumber *clCheckBoxVerticalAlignmentToAppPrivacyCenterY;

CheckBox大小调整
直接设置size:clCheckBoxSize = [NSValue valueWithCGSize:CGSizeMake(25, 25)];

对齐方式(相对协议控件)
clCheckBoxVerticalAlignmentToAppPrivacyTop : 顶部对齐
clCheckBoxVerticalAlignmentToAppPrivacyCenterY :垂直中心对齐

勾选框图片位置微调

原理:CheckBox为标准UIButton控件,clCheckBoxImageEdgeInsets属性设置实际是进行[UIButton setImageEdgeInsets:];操作。

clCheckBoxImageEdgeInsets = [NSValue valueWithUIEdgeInsets:UIEdgeInsetsMake(2, 2, 2, 2)];

截屏2020-05-29上午10.34.59.png

四.本机认证


## 1.初始化 **同**`**二、SDK使用说明**`**-->**`**初始化**` ## 2.本机认证 方法原型
/**
 本机号码校验
 @param complete 校验回调
 */
+ (void)mobileCheckWithLocalPhoneNumberComplete:(CLComplete)complete;

参数描述

参数 是否必填 类型 说明
complete 必填 CLComplete 获取token回调,回调token信息

接口作用

本机号码校验 :验证指定手机号与本机SIM卡是否一致。(此接口仅返回token,手机号验证需调用服务端)

使用场景

  • 在初始化接口后调用
  • 输入手机号后进行校验

请求示例代码

ObjC:

  1. 导入闪验SDK头文件 #import <CL_ShanYanSDK/CL_ShanYanSDK.h>

[CLShanYanSDKManager mobileCheckWithLocalPhoneNumberComplete:^(CLCompleteResult * _Nonnull completeResult) {

    if (completeResult.error) {
       NSLog(@"mobileCheckWithLocalPhoneNumber:%@\n",completeResult.error.description);
    }else{
       NSLog(@"mobileCheckWithLocalPhoneNumber:%@\n",completeResult.yy_modelToJSONObject);
       //调服务端接口,发送token,验证手机号
       [weakSelf checkPhonenumber:completeResult.data];
    }
}];


//此处模拟客户服务端调用闪验服务端,依照闪验服务端文档,实际情景下,app需要调用自己的服务端接口,将整个token传给服务端,整个token的验证在客户服务端进行,客户服务端将结果返回给app
- (void)checkPhonenumber:(NSDictionary *)completeResultData{

    NSLog(@"tokenParamr:%@",completeResultData);

    NSMutableDictionary * paramr = [NSMutableDictionary dictionaryWithDictionary:completeResultData];
    paramr[@"appId"] = cl_SDK_APPID;
    paramr[@"mobile"] = _phoneNumberField.text;

    NSMutableString *formDataString = [NSMutableString new];
    NSArray * keys = [paramr.allKeys sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
        NSString * objString1 = [NSString stringWithFormat:@"%@",obj1];
        NSString * objString2 = [NSString stringWithFormat:@"%@",obj2];
        return [objString1 compare:objString2];
    }];
    for (NSString * key in keys) {
        [formDataString appendString:key];
        [formDataString appendString:paramr[key]];
    }
    
    CocoaSecurityResult * hmacSha256Result = [CocoaSecurity hmacSha256:formDataString hmacKey:cl_SDK_APPKEY];
    paramr[@"sign"] = hmacSha256Result.hex;

    NSLog(@"%@",paramr);
    __weak typeof(self) weakSelf = self;
    [NetWorkManager POST_url:cl_SDK_URL_MobileValidate withParameter:paramr complete:^(NSDictionary * _Nonnull responseObject, NSError * _Nonnull error) {
        
        dispatch_async(dispatch_get_main_queue(), ^{
            [CLHUD hideLoading:weakSelf.view];
        });
        
        NSString * message ;
        if (error) {
            message = [NSString stringWithFormat:@"cl_SDK_MobileValidate:%@\n本机校验失败\n",error.description];
        }else{
            NSInteger code = [[responseObject valueForKey:@"code"] integerValue];
            if (code == 200000) {
                if ([responseObject[@"data"][@"isVerify"] integerValue] == 1) {
                    //本机校验成功,号码一致

                    message = [NSString stringWithFormat:@"cl_SDK_MobileValidate:%@\n本机校验成功,号码一致\n",responseObject.description];
                }else{
                    //本机校验失败,号码不一致

                    message = [NSString stringWithFormat:@"cl_SDK_MobileValidate:%@\n本机校验失败,号码不一致\n",responseObject.description];
                }
            }else{

                //本机校验失败
                message = [NSString stringWithFormat:@"cl_SDK_MobileValidate:%@\n本机校验失败\n",responseObject.description];
            }
            
        }
        dispatch_async(dispatch_get_main_queue(), ^{
              CLConsoleLog(@"%@",message);
              [CLHUD showMessage:weakSelf.view message:message];
        });
    }];
}

3.手机号后台服务端校验

以下为代码块–完整方法请参考步骤 2.本机认证

- (void)getPhonenumber:(NSDictionary *)completeResultData{

	// 
    NSMutableDictionary * paramr = [NSMutableDictionary dictionaryWithDictionary:completeResultData];
    paramr[@"appId"] = cl_SDK_APPID;
    
    //URLEncode
    NSMutableString *formDataString = [NSMutableString new];
    [paramr enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        NSString * objString = [NSString stringWithFormat:@"%@",obj];
        [formDataString appendString:[NSString stringWithFormat:@"%@=%@&", key, objString]];
    }];
    NSLog(@"%@",paramr);
    __weak typeof(self) weakSelf = self;
    NSString * url = [NSString stringWithFormat:@"%@%@",cl_SDK_URL,cl_SDK_MobileQuery];
    [NetWorkManager POST_url:url withParameter:paramr complete:^(NSDictionary * _Nonnull responseObject, NSError * _Nonnull error) {
        
        [weakSelf hideShanYanAuthPageMaskViewWhenUseWindow];
        //关闭授权页
        [CLShanYanSDKManager finishAuthControllerAnimated:YES Completion:nil];

        if (error) {
            CLConsoleLog(@"%@",error);
        }else{
            //    "retCode": "0",
            //    "retMsg": "成功",
            //    "data": {
            //        "mobileName": "18888888888"
            //    }
            NSInteger retCode = [[responseObject valueForKey:@"retCode"] integerValue];
            if (retCode == 0) {
                NSString * mobileName = responseObject[@"data"][@"mobileName"];
                CLConsoleLog(@"免密登录成功,手机号:%@",mobileName);
                dispatch_async(dispatch_get_main_queue(), ^{
                    [CLHUD showMessage:weakSelf.view message:[NSString stringWithFormat:@"免密登录成功,手机号:%@",mobileName]];
                });
            } else {
                CLConsoleLog(@"免密登录失败:%@",responseObject);
            }
        }
    }];
}

五.返回码对照

外层错误码

同一外层码可能对应不同的内层码

外层返回码 返回码描述
1000 一键登录成功,解析result,可得到网络请求参数
1011 用户取消免密登录(点击返回按钮)
1001 SDK初始化失败
1023 预取号/取号失败
1003 拉起授权页失败/一键登录失败/获取token失败
1008 未开启移动网络
1032 账户禁用
2000 本机校验:获取token成功
2001 本机校验:手机号码为空
2003 本机校验:联通获取token失败
2004 本机校验:电信获取token失败
2005 本机校验:移动获取token失败
2009 本机校验:非三大运营商
2023 本机校验:未开启移动网络
其他 其他错误

内层错误码

联通返回码

状态码 报错信息
100
成功(有数据返回)
111
认证失败(手机号码和认证手机号码不一致,计费)
112
认证失败(认证但未取到手机号码)
1101
公网 ip 无效(客户 wifi 访问、wap 方式访问等引起获取到的公网 ip 查询不到省份信息)
1102
私网 ip 无效(无法用私网 ip 找到对应的省份信息)
1103
待认证的手机号不能为空(认证传入的手机号码为空)
1104
授权码为空(传入的授权码为空)
1105
参数信息错误(参数名称、内容错误或者参数丢失再或者加密错误)
1106
应用密钥信息不匹配(密钥信息与包名不一致,android 还需要校验 MD5 信息,也有可能是参数命名错误)
1107
余额不足(使用条数不足)
1108
调用能力不匹配(取号置换码调用认证能力或者反之)
1201
取号失败
1202
认证失败
1203
获取置换码失败
2101
鉴权失败(参数 sign 名称错误或者 sign 值有误)
2102
accessCode 已失效(accessCode 错误或者过期)
2103
序列号不存在(序列号与授权码和密钥绑定,序列号不存在时返回,即授权码错误或者密钥信息与前台使用 不是一套,或者 seq 已过期)
2201
app_id 无效(appid 未激活或者 appid 错误)
2202
应用信息错误(获取应用信息错误(demo 中 data 参数中 app 信息错误))
2203
sdk 信息错误(获取 sdk 信息错误(demo 中 data 参数中 sdk 信息错误))
2205
接入信息解析错误(用户接入信息解析失败)
2206
流控值超限(用户访问流控超过限制)
3201
系统繁忙(服务端系统出现错误)
3202
内部网关错误
3203
内部路由错误
3204
无支付权限
3206
取号功能暂时不可用
3207
不支持此功能
10100
无网络连接
10101
无数据网络连接
10102
ApiKey 或 PublicKey 不能为空
10103
超时
10104
用户取消登录
10105
切换登录方式
10106
数据解密异常(SDK 解密数据失败)
10107
打开授权页
10110
取号中(正在取号中)
20100
测试次数超限
20101
10 分钟之内最多只能获取 30 个授权码
30200
服务端数据格式出错

电信返回码

返回码 返回描述
0 请求成功
-64 permission-denied(无权限访问)
-65 API-request-rates-Exceed-Limitations(调用接口超限)
-10001 取号失败
-10002 参数错误
-10003 解密失败
-10004 ip受限
-10005 异网取号回调参数异常
-10006 Mdn取号失败,且属于电信网络
-10007 重定向到异网取号
-10008 超过预设取号阈值
-10009 时间戳过期
-20005 sign-invalid(签名错误)
-20006 应用不存在
-20007 公钥数据不存在
-20100 内部解析错误
-20102 加密参数解析失败
-30001 时间戳非法
-30003 topClass 失效
51002 参数为空
51114 无法获取手机号
80000 请求超时
80001 请求网络异常
80002 响应码错误
80003 无网络连接
80004 移动网络未开启
80005 Socket 超时异常
80006 域名解析异常
80007 IO 异常
80008 No route to host
80009 nodename nor

移动返回码

返回码 返回码描述
103000 成功
103101 请求签名错误
103102 包签名/Bundle ID错误
103108 短信验证码错误
103109 短信验证码校验超时
103111 网关IP错误
103119 appid不存在
103125 短验下发时,手机号填写格式错误
103211 其他错误,(如有需要请联系qq群609994083内的移动认证开发)
103902 scrip失效
103911 token请求过于频繁,10分钟内获取token且未使用的数量不超过30个
103273 预取号联通重定向(暂不支持联通取号)
105002 移动取号失败
105003 电信取号失败
105021 已达当天取号限额
105302 appid不在白名单
105313 非法请求
200020 用户取消登录
200021 数据解析异常
200022 无网络
200023 请求超时
200025 其他错误(socket、系统未授权数据蜂窝权限等,如需要协助,请加入qq群发问)
200027 未开启数据网络
200028 网络请求出错
200038 异网取号网络请求失败
200048 用户未安装sim卡
200050 EOF异常
200060 切换账号(未使用SDK短验时返回)
200061 授权页面异常
200064 服务端返回数据异常
200072 CA根证书校验失败
200080 本机号码校验仅支持移动手机号
200082 服务器繁忙
200086 ppLocation为空
200087 授权页成功拉起
200089 SDK正在处理

六.已知问题

更多问题查询请移步至【常见问题】

1.ATS开关(Http与Https)
目前运营商个别接口为http请求,对于全局禁用Http的项目,需要设置Http白名单。以下为运营商http接口host名单:
*.cmpassport.com、id6.me、123.125.99.8:9001、ms.zzx9.cnmdn.open.wo.cn、10.99.255.231,*为通配符,建议按以下方式配置Info.plist

<key>NSAppTransportSecurity</key>
	<dict>
		<key>NSExceptionDomains</key>
		<dict>
			<key>zzx9.cn</key>
			<dict>
				<key>NSIncludesSubdomains</key>
				<true/>
				<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
				<true/>
			</dict>
			<key>cmpassport.com</key>
			<dict>
				<key>NSIncludesSubdomains</key>
				<true/>
				<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
				<true/>
			</dict>
			<key>id6.me</key>
			<dict>
				<key>NSIncludesSubdomains</key>
				<true/>
				<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
				<true/>
			</dict>
			<key>wostore.cn</key>
			<dict>
				<key>NSIncludesSubdomains</key>
				<true/>
				<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
				<true/>
			</dict>
			<key>mdn.open.wo.cn</key>
			<dict>
				<key>NSIncludesSubdomains</key>
				<true/>
				<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
				<true/>
			</dict>
		</dict>
	</dict>

2.联通预取号崩溃【预取号+联通+崩溃、NSDictionary + setObject、空指针】
联通SDK内部会读取校验info.plist文件中Bundle identifier、Bundle name、Bundle versions string, short、Bundle version字段,如未配置相关字段Value会导致以下崩溃
image.png

image.png