文档反馈
文档反馈

iOS v1.0.0(网易云信)

概述

当前版本:1.0.0

一.准备工作

升级指南

手动集成闪验所有版本通用方式: 替换SDK静态库: 删除旧版本SDK所有相关的.framework`.bundle文件,清除缓存,再导入新版SDK中的所有.framework.bundle`文件(.bundle文件注意保留开发者自定义资源)

前置条件

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

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

创建应用

提供信息:

获取信息:

快速体验Demo

将获得的AppID填入Demo工程中,修改工程BundleID为绑定的BundleID即可。

开发环境搭建

手动集成

  1. 导入framework: 将网易SDK压缩包中framework文件夹下所有资源添加到工程中(注意勾选Copy items if needed)
  2. Xcode配置:
  3. OtherLinkerFlags中 添加-ObjC:Xcode->BuildSetting->Other Linker Flags 添加 -ObjC
  4. 添加libc++.1.tbd: 在xcode->General->Linked Frameworks and Libraries中点击 + ,搜索并选择添加 libc++.1.tbd

二.SDK使用说明

登录流程图概览:

SDK技术逻辑

1.初始化

使用场景

请求示例代码

  1. 导入网易SDK头文件 #import <YXLoginSDK/YXLoginSDK.h>
  2. 在AppDelegate中的 didFinishLaunchingWithOptions方法中添加初始化代码 `objectivec
  3. (BOOL)application:(UIApplication )application didFinishLaunchingWithOptions:(NSDictionary )launchOptions { ... //初始化 [YXLManager initWithAppId:"xx" complete:^(YXLCompleteResult * _Nonnull completeResult) {

    }];
    /**

    • 建议在退出登录时再次调用初始化方法 */ ... } `

2.预取号

不建议 频繁的多次调用和在拉起授权页后调用 预取号方法回调中处理UI操作需手动切换到主线程

接口作用

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

使用场景

请求示例代码

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

3.拉起授权页

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

/**
 一键登录拉起内置授权页&获取Token( 区分拉起授权页之前和之后的回调)

 @param yxlUIConfig 授权页参数配置
 @param openLoginAuthListener 拉起授权页监听:拉起授权页面成功或失败的回调,拉起成功或失败均触发。当拉起失败时,oneKeyLoginListener不会触发。此回调的内部触发时机是viewDidAppear

 @param oneKeyLoginListener 一键登录监听:拉起授权页成功后的后续操作回调,包括点击SDK内置的(非外部自定义)取消登录按钮,以及点击本机号码一键登录的回调。点击授权页自定义按钮不触发此回调

 * 回调中如需UI操作,建议自行切到主线程
 */
+(void)quickAuthLoginWithConfigure:(YXLUIConfig *)yxlUIConfig
             openLoginAuthListener:(YXLComplete)openLoginAuthListener
               oneKeyLoginListener:(YXLComplete)oneKeyLoginListener;

参数描述

参数 类型 说明
YXLUIConfig (必填) YXLUIConfig 授权页控件属性配置对象
openLoginAuthListener (选填) YXLComplete 拉起授权页的回调,拉起页面成功、失败均触发
oneKeyLoginListener (必填) YXLComplete 一键登录回调,用于接收一键登录的结果,点一键登录成功、失败均触发,点自带的返回按钮也触发

使用场景

一键登录逻辑说明

请求示例代码

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

    __weak typeof(self) weakself = self;

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

    YXLUIConfig * baseUIConfigure = [YXLUIConfig new];
    baseUIConfigure.viewController = self;
    baseUIConfigure.logoImage = [UIImage imageNamed:@"your_app_logo_image"];

    baseUIConfigure.appPrivacyFirst = @[@"测试连接1",[NSURL URLWithString:@"https://baidu.com"]];
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Index" ofType:@"html"];
    //baseUIConfigure.appPrivacySecond = @[@"测试连接2",[NSURL URLWithString:@"https://sina.com"]];
    baseUIConfigure.appPrivacySecond = @[@"本地协议地址",[NSURL fileURLWithPath:filePath]];

    //layout 布局
    YXLLayout * layoutPortrait = [YXLLayout new];
    layoutPortrait.phoneCenterY = @(0*screenScale);
    layoutPortrait.phoneLeft = @(50*screenScale);
    ...
    baseUIConfigure.layoutPortrait = layoutPortrait;

    // show loading...

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

            if (completeResult.error) {
                //一键登录失败
                NSLog(@"oneKeyLoginListener:%@",completeResult.error.description);

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

                //SDK成功获取到Token,请求用户APP服务端置换手机号。
                /** 
                code
                */
            }
        }];
 }
返回参数示例 completeResult.data
{
    token = "A3-KqvM4yO_lApRLwpv4qVNnBRF3w=="
}
字段 类型 含义
token String token,置换令牌,用来和后台置换手机号。一次有效,有效期3min

授权页销毁

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

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

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

sdk获取token回调后销毁界面

//关闭页面
[YXLManager 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];
}];
YXLManager.quickAuthLogin(with: yxlUIConfig, openLoginAuthListener: { (completeResult) in
    ...
}) { (completeResult) in 

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

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

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

4.手动关闭授权页

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

//方式1
[self.PresentedViewController dismissViewControllerAnimated:YES completion:nil];

//方式二
[YXLManager 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];
}];
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 ()

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

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

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

/**
 * 统一事件监听方法
 * type:事件类型(1,2,3)
 * 1:隐私协议点击
 * - 同-yxlWebPrivacyClicked:privacyIndex:currentTelecom
 * code:0,1,2,3(协议页序号),message:协议名_当前运营商类型
 * 2:协议勾选框点击
 * code:0,10为未选中,1为选中)
 * 3"一键登录"按钮点击
 * code:0,10为协议勾选框未选中,1为选中)
*/
-(void)yxlActionListener:(NSInteger)type code:(NSInteger)code  message:(NSString *_Nullable)message;  message:(NSString *_Nullable)message;

协议点击监听方式二

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

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

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

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

三.授权界面修改

1.设计规范

设计规范

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

2.页面可调整属性、布局

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

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

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

/**授权页-背景图片*/
@property (nonatomic,strong) UIImage *authVCBackgroundImg;
/**授权页-背景色*/
@property (nonatomic,strong) UIColor *authVCBackgroundColor;

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

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

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

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

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


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

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

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



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

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

/*一键登录按钮 控件
 注: 一键登录授权按钮 不得隐藏
 **/
/**按钮文字*/
@property (nonatomic,copy)NSString   * loginBtnText;
/**按钮文字颜色*/
@property (nonatomic,strong)UIColor  * loginBtnTextColor;
/**按钮背景颜色*/
@property (nonatomic,strong)UIColor  * loginBtnBgColor;
/**按钮文字字体*/
@property (nonatomic,strong)UIFont   * loginBtnTextFont;
/**按钮背景图片*/
@property (nonatomic,strong)UIImage  * loginBtnNormalBgImage;
/**按钮背景高亮图片*/
@property (nonatomic,strong)UIImage  * loginBtnHightLightBgImage;
/**按钮背景不可用图片*/
@property (nonatomic,strong)UIImage  * loginBtnDisabledBgImage;
/**按钮边框颜色*/
@property (nonatomic,strong)UIColor  * loginBtnBorderColor;
/**按钮圆角 CGFloat eg.@(5)*/
@property (nonatomic,strong)NSNumber * loginBtnCornerRadius;
/**按钮边框 CGFloat eg.@(2.0)*/
@property (nonatomic,strong)NSNumber * loginBtnBorderWidth;

/*隐私条款Privacy
 注: 运营商隐私条款 不得隐藏
 用户条款不限制
 **/
/**隐私条款 下划线设置,默认隐藏,设置privacyShowUnderline = @(YES)显示下划线*/
@property (nonatomic,strong)NSNumber * privacyShowUnderline;
/**隐私条款名称颜色:@[基础文字颜色UIColor*,条款颜色UIColor*] eg.@[[UIColor lightGrayColor],[UIColor greenColor]]*/
@property (nonatomic,strong) NSArray<UIColor*> *appPrivacyColor;
/**隐私条款文字字体*/
@property (nonatomic,strong)UIFont  * appPrivacyTextFont;
/**隐私条款文字对齐方式 NSTextAlignment eg.@(NSTextAlignmentCenter)*/
@property (nonatomic,strong)NSNumber * appPrivacyTextAlignment;
/**运营商隐私条款书名号 默认NO 不显示 BOOL eg.@(YES)*/
@property (nonatomic,strong)NSNumber * appPrivacyPunctuationMarks;
/**多行时行距 CGFloat eg.@(2.0)*/
@property (nonatomic,strong)NSNumber* appPrivacyLineSpacing;
/**是否需要sizeToFit,设置后与宽高约束的冲突请自行考虑 BOOL eg.@(YES)*/
@property (nonatomic,strong)NSNumber* appPrivacyNeedSizeToFit;
/**UITextView.textContainerInset 文字与TextView控件内边距 UIEdgeInset  eg.[NSValue valueWithUIEdgeInsets:UIEdgeInsetsMake(2, 2, 2, 2)]*/
@property (nonatomic,strong)NSValue* appPrivacyTextContainerInset;

/**隐私条款--APP名称简写 默认取CFBundledisplayname 设置描述文本四后此属性无效*/
@property (nonatomic,copy) NSString  * appPrivacyAbbreviatedName;
/*
 *隐私条款Y一:需同时设置Name和UrlString eg.@[@"条款一名称",条款一URL]
 *@[NSSting,NSURL];
 */
@property (nonatomic,strong)NSArray * appPrivacyFirst;
/*
 *隐私条款二:需同时设置Name和UrlString eg.@[@"条款一名称",条款一URL]
 *@[NSSting,NSURL];
 */
@property (nonatomic,strong)NSArray * appPrivacySecond;
/*
 *隐私条款三:需同时设置Name和UrlString eg.@[@"条款一名称",条款一URL]
 *@[NSSting,NSURL];
 */
@property (nonatomic,strong)NSArray * appPrivacyThird;
/*
 隐私协议文本拼接: DesTextFirst+运营商条款+DesTextSecond+隐私条款一+DesTextThird+隐私条款二+DesTextFourth+隐私条款三+DesTextLast
 **/
/**描述文本 首部 default:"同意"*/
@property (nonatomic,copy)NSString *appPrivacyNormalDesTextFirst;
/**描述文本二 default:"和"*/
@property (nonatomic,copy)NSString *appPrivacyNormalDesTextSecond;
/**描述文本三 default:"、"*/
@property (nonatomic,copy)NSString *appPrivacyNormalDesTextThird;
/**描述文本四 default:"、"*/
@property (nonatomic,copy)NSString *appPrivacyNormalDesTextFourth;
/**描述文本 尾部 default: "并授权AppName使用认证服务"*/
@property (nonatomic,copy)NSString *appPrivacyNormalDesTextLast;

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

/**用户隐私协议WEB页面导航栏标题 默认显示用户条款名称*/
@property (nonatomic,strong)NSAttributedString * appPrivacyWebAttributesTitle;
/**运营商隐私协议WEB页面导航栏标题 默认显示运营商条款名称*/
@property (nonatomic,strong)NSAttributedString * appPrivacyWebNormalAttributesTitle;
/**自定义协议标题-按自定义协议对应顺序*/
@property (nonatomic,strong)NSArray<NSString*> * appPrivacyWebTitleList;

/**隐私协议标题文本属性(用户协议&&运营商协议)*/
@property (nonatomic,strong)NSDictionary * appPrivacyWebAttributes;
/**隐私协议WEB页面导航返回按钮图片*/
@property (nonatomic,strong)UIImage * appPrivacyWebBackBtnImage;

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

/**UINavigationTintColor*/
@property (nonatomic,strong)UIColor  * appPrivacyWebNavigationTintColor;
/**UINavigationBarTintColor*/
@property (nonatomic,strong)UIColor  * appPrivacyWebNavigationBarTintColor;
/**UINavigationBackgroundImage*/
@property (nonatomic,strong)UIImage  * appPrivacyWebNavigationBackgroundImage;
/**UINavigationBarMetrics*/
@property (nonatomic,strong)NSNumber * appPrivacyWebNavigationBarMetrics;
/**UINavigationShadowImage*/
@property (nonatomic,strong)UIImage  * appPrivacyWebNavigationShadowImage;
/**UINavigationBarStyle*/
@property (nonatomic,strong)NSNumber * appPrivacyWebNavigationBarStyle;

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

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

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



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

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

/*Loading*/
/**Loading 大小 CGSize eg.[NSValue valueWithCGSize:CGSizeMake(50, 50)]*/
@property (nonatomic,strong) NSValue *loadingSize;
/**Loading 圆角 float eg.@(5) */
@property (nonatomic,strong) NSNumber *loadingCornerRadius;
/**Loading 背景色 UIColor eg.[UIColor colorWithRed:0.8 green:0.5 blue:0.8 alpha:0.8]; */
@property (nonatomic,strong) UIColor *loadingBackgroundColor;
/**UIActivityIndicatorViewStyle eg.@(UIActivityIndicatorViewStyleWhiteLarge)*/
@property (nonatomic,strong) NSNumber *loadingIndicatorStyle;
/**Loading Indicator渲染色 UIColor eg.[UIColor greenColor]; */
@property (nonatomic,strong) UIColor *loadingTintColor;
/**授权页自定义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
 - 如果设置只支持竖屏,只需设置layoutPortrait竖屏布局对象
 - 如果设置只支持横屏,只需设置layoutLandscape横屏布局对象
 - 横竖屏均支持,需同时设置layoutPortrait和layoutLandscape
 */
@property (nonatomic,strong) NSNumber * supportedInterfaceOrientations;
/*默认方向 UIInterfaceOrientation*/
@property (nonatomic,strong) NSNumber * preferredInterfaceOrientationForPresentation;

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

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

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

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

/**
 * 授权页面present弹出时animate动画设置,默认带动画,eg. @(YES)
 */
@property (nonatomic,strong) NSNumber * authWindowPresentingAnimate;
/**
 * sdk自带返回键:授权页面dismiss时animate动画设置,默认带动画,eg. @(YES)
 */
@property (nonatomic,strong) NSNumber * authWindowDismissAnimate;

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


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

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


/**默认界面配置*/
+ (YXLUIConfig *)defaultUIConfig;

页面布局

/**横竖屏布局配置对象
 配置页面布局相关属性
 */
@interface YXLLayout : NSObject
/**LOGO图片*/
// 约束均相对vc.view
@property (nonatomic,strong)NSNumber * logoLeft;
@property (nonatomic,strong)NSNumber * logoTop;
@property (nonatomic,strong)NSNumber * logoRight;
@property (nonatomic,strong)NSNumber * logoBottom;
@property (nonatomic,strong)NSNumber * logoWidth;
@property (nonatomic,strong)NSNumber * logoHeight;
@property (nonatomic,strong)NSNumber * logoCenterX;
@property (nonatomic,strong)NSNumber * logoCenterY;

/**手机号显示控件*/
//layout 约束均相对vc.view
@property (nonatomic,strong)NSNumber * phoneLeft;
@property (nonatomic,strong)NSNumber * phoneTop;
@property (nonatomic,strong)NSNumber * phoneRight;
@property (nonatomic,strong)NSNumber * phoneBottom;
@property (nonatomic,strong)NSNumber * phoneWidth;
@property (nonatomic,strong)NSNumber * phoneHeight;
@property (nonatomic,strong)NSNumber * phoneCenterX;
@property (nonatomic,strong)NSNumber * phoneCenterY;

/*一键登录按钮 控件
 注: 一键登录授权按钮 不得隐藏
 **/
//layout 约束均相对vc.view
@property (nonatomic,strong)NSNumber * loginBtnLeft;
@property (nonatomic,strong)NSNumber * loginBtnTop;
@property (nonatomic,strong)NSNumber * loginBtnRight;
@property (nonatomic,strong)NSNumber * loginBtnBottom;
@property (nonatomic,strong)NSNumber * loginBtnWidth;
@property (nonatomic,strong)NSNumber * loginBtnHeight;
@property (nonatomic,strong)NSNumber * loginBtnCenterX;
@property (nonatomic,strong)NSNumber * loginBtnCenterY;

/*隐私条款Privacy
 注: 运营商隐私条款 不得隐藏, 用户条款不限制
 **/
//layout 约束均相对vc.view
@property (nonatomic,strong)NSNumber * appPrivacyLeft;
@property (nonatomic,strong)NSNumber * appPrivacyTop;
@property (nonatomic,strong)NSNumber * appPrivacyRight;
@property (nonatomic,strong)NSNumber * appPrivacyBottom;
@property (nonatomic,strong)NSNumber * appPrivacyWidth;
@property (nonatomic,strong)NSNumber * appPrivacyHeight;
@property (nonatomic,strong)NSNumber * appPrivacyCenterX;
@property (nonatomic,strong)NSNumber * appPrivacyCenterY;

/*Slogan 运营商品牌标签:"认证服务由中国移动/联通/电信提供" label
 注: 运营商品牌标签,不得隐藏
 **/
//layout 约束均相对vc.view
@property (nonatomic,strong)NSNumber * sloganLeft;
@property (nonatomic,strong)NSNumber * sloganTop;
@property (nonatomic,strong)NSNumber * sloganRight;
@property (nonatomic,strong)NSNumber * sloganBottom;
@property (nonatomic,strong)NSNumber * sloganWidth;
@property (nonatomic,strong)NSNumber * sloganHeight;
@property (nonatomic,strong)NSNumber * sloganCenterX;
@property (nonatomic,strong)NSNumber * sloganCenterY;

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

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

3.横竖屏设置

相关设置属性

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

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

#pragma mark - 横竖屏及旋转方向设置
- (YXLUIConfig *)configureStyle3:(YXLUIConfig *)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;
    }
    YXLUIConfig * baseUIConfigure = inputConfigure ? inputConfigure : [YXLUIConfig new];
    baseUIConfigure.viewController = self;
    ...

    //layout 布局
    //布局-竖屏
    YXLLayout * layoutPortrait = [[YXLLayout alloc]init];

    //窗口中心
    layoutPortrait.authWindowCenter = [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
    layoutPortrait.authWindowWidth = @(authWindowWidth_Portrait);
    layoutPortrait.authWindowHeight = @(authWindowHeight_Portrait);

    layoutPortrait.logoWidth = @(60*screenScale);
    layoutPortrait.logoHeight = @(60*screenScale);
    layoutPortrait.logoCenterX = @(0);
    layoutPortrait.logoTop = @(25*screenScale);


    layoutPortrait.phoneCenterY = @(-20*screenScale);
    layoutPortrait.phoneLeft = @(50*screenScale);
    layoutPortrait.phoneRight = @(-50*screenScale);
    layoutPortrait.phoneHeight = @(20*screenScale);
//    layoutPortrait.phoneTop = @(64*screenScale);

    layoutPortrait.loginBtnCenterY= @(layoutPortrait.phoneCenterY.floatValue + layoutPortrait.phoneHeight.floatValue*0.5*screenScale + 20*screenScale + 15*screenScale);
    layoutPortrait.loginBtnHeight = @(30*screenScale);
    layoutPortrait.loginBtnLeft = @(70*screenScale);
    layoutPortrait.loginBtnRight = @(-70*screenScale);

    layoutPortrait.appPrivacyLeft = @(40*screenScale);
    layoutPortrait.appPrivacyRight = @(-40*screenScale);
    layoutPortrait.appPrivacyBottom = @(0*screenScale);
    layoutPortrait.appPrivacyHeight = @(45*screenScale);

    layoutPortrait.sloganLeft = @(0);
    layoutPortrait.sloganRight = @(0);
    layoutPortrait.sloganHeight = @(15*screenScale);
    layoutPortrait.sloganBottom = @(layoutPortrait.appPrivacyBottom.floatValue - layoutPortrait.appPrivacyHeight.floatValue);


    //布局-横屏
    YXLLayout * layoutLandscape = [YXLLayout new];

    //窗口中心
    layoutLandscape.authWindowCenter = [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
    layoutLandscape.authWindowWidth = @(authWindowWidth_Landscape);
    layoutLandscape.authWindowHeight = @(authWindowHeight_Landscape);

    layoutLandscape.logoWidth = @(60*screenScale);
    layoutLandscape.logoHeight = @(60*screenScale);
    layoutLandscape.logoCenterX = @(0);
    layoutLandscape.logoTop = @(25*screenScale);

    layoutLandscape.phoneCenterY = @(-20*screenScale);
    layoutLandscape.phoneLeft = @(50*screenScale);
    layoutLandscape.phoneRight = @(-50*screenScale);
    layoutLandscape.phoneHeight = @(20*screenScale);

    layoutLandscape.loginBtnCenterY= @(layoutLandscape.phoneCenterY.floatValue + layoutLandscape.phoneHeight.floatValue*0.5*screenScale + 20*screenScale + 15*screenScale);
    layoutLandscape.loginBtnHeight = @(30*screenScale);
    layoutLandscape.loginBtnLeft = @(70*screenScale);
    layoutLandscape.loginBtnRight = @(-70*screenScale);

    layoutLandscape.appPrivacyLeft = @(40*screenScale);
    layoutLandscape.appPrivacyRight = @(-40*screenScale);
    layoutLandscape.appPrivacyBottom = @(0*screenScale);
    layoutLandscape.appPrivacyHeight = @(45*screenScale);

    layoutLandscape.sloganLeft = @(0);
    layoutLandscape.sloganRight = @(0);
    layoutLandscape.sloganHeight = @(15*screenScale);
    layoutLandscape.sloganBottom = @(layoutLandscape.appPrivacyBottom.floatValue - layoutLandscape.appPrivacyHeight.floatValue);


    baseUIConfigure.layoutPortrait = layoutPortrait;
    baseUIConfigure.layoutLandscape = layoutLandscape;
    return baseUIConfigure;
}

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

#pragma mark - 样式3:窗口样式
- (YXLUIConfig *)configureStyle3:(YXLUIConfig *)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;
    }

    YXLUIConfig * baseUIConfigure = inputConfigure;

    baseUIConfigure.checkBoxValue = @(YES);

    //横竖屏旋转方向设置
    baseUIConfigure.shouldAutorotate = @(YES);
    baseUIConfigure.supportedInterfaceOrientations = @(UIInterfaceOrientationMaskAll);
    //baseUIConfigure.preferredInterfaceOrientationForPresentation = @(UIInterfaceOrientationLandscapeLeft);

    //使用窗口方式
    baseUIConfigure.authTypeUseWindow = @(YES);
    baseUIConfigure.authWindowCornerRadius = @(20);
    baseUIConfigure.authWindowModalTransitionStyle = @(UIModalTransitionStyleCoverVertical);

    /****页面元素配置****/
    baseUIConfigure.authVCBackgroundImg = [UIImage imageNamed:@"eb9a0dae18491990a43fe02832d3cafa"];
    baseUIConfigure.navigationBackgroundClear = @(YES);
    baseUIConfigure.navigationBackBtnHidden = @(YES);
    baseUIConfigure.navigationBottomLineHidden = @(YES);
    // 自定义协议加载
    baseUIConfigure.appPrivacyFirst = @[@"测试连接1",[NSURL URLWithString:@"https://baidu.com"]];
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Index" ofType:@"html"];
    //baseUIConfigure.appPrivacySecond = @[@"测试连接2",[NSURL URLWithString:@"https://sina.com"]];
    baseUIConfigure.appPrivacySecond = @[@"本地协议地址",[NSURL fileURLWithPath:filePath]];

    ...

    /****横竖屏布局配置****/

    //布局-竖屏
    YXLLayout * layoutPortrait = [YXLLayout new];

    //窗口中心
    layoutPortrait.authWindowCenter = [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
    layoutPortrait.authWindowWidth = @(authWindowWidth_Portrait);
    layoutPortrait.authWindowHeight = @(authWindowHeight_Portrait);

    layoutPortrait.logoWidth = @(60*screenScale);
    layoutPortrait.logoHeight = @(60*screenScale);
    layoutPortrait.logoCenterX = @(0);
    layoutPortrait.logoTop = @(25*screenScale);

    layoutPortrait.phoneCenterY = @(-20*screenScale);
    layoutPortrait.phoneLeft = @(50*screenScale);
    layoutPortrait.phoneRight = @(-50*screenScale);
    layoutPortrait.phoneHeight = @(20*screenScale);

    layoutPortrait.loginBtnCenterY= @(layoutPortrait.phoneCenterY.floatValue + layoutPortrait.phoneHeight.floatValue*0.5*screenScale + 20*screenScale + 15*screenScale);
    layoutPortrait.loginBtnHeight = @(30*screenScale);
    layoutPortrait.loginBtnLeft = @(70*screenScale);
    layoutPortrait.loginBtnRight = @(-70*screenScale);

    layoutPortrait.appPrivacyLeft = @(40*screenScale);
    layoutPortrait.appPrivacyRight = @(-40*screenScale);
    layoutPortrait.appPrivacyBottom = @(0*screenScale);
    layoutPortrait.appPrivacyHeight = @(45*screenScale);

    layoutPortrait.sloganLeft = @(0);
    layoutPortrait.sloganRight = @(0);
    layoutPortrait.sloganHeight = @(15*screenScale);
    layoutPortrait.sloganBottom = @(layoutPortrait.appPrivacyBottom.floatValue - layoutPortrait.appPrivacyHeight.floatValue);

    //布局-横屏
    YXLLayout * layoutLandscape = [YXLLayout new];

    //窗口中心
    layoutLandscape.authWindowCenter = [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
    layoutLandscape.authWindowWidth = @(authWindowWidth_Landscape);
    layoutLandscape.authWindowHeight = @(authWindowHeight_Landscape);

    layoutLandscape.logoWidth = @(60*screenScale);
    layoutLandscape.logoHeight = @(60*screenScale);
    layoutLandscape.logoCenterX = @(0);
    layoutLandscape.logoTop = @(25*screenScale);

    layoutLandscape.phoneCenterY = @(-20*screenScale);
    layoutLandscape.phoneLeft = @(50*screenScale);
    layoutLandscape.phoneRight = @(-50*screenScale);
    layoutLandscape.phoneHeight = @(20*screenScale);

    layoutLandscape.loginBtnCenterY= @(layoutLandscape.phoneCenterY.floatValue + layoutLandscape.phoneHeight.floatValue*0.5*screenScale + 20*screenScale + 15*screenScale);
    layoutLandscape.loginBtnHeight = @(30*screenScale);
    layoutLandscape.loginBtnLeft = @(70*screenScale);
    layoutLandscape.loginBtnRight = @(-70*screenScale);

    layoutLandscape.appPrivacyLeft = @(40*screenScale);
    layoutLandscape.appPrivacyRight = @(-40*screenScale);
    layoutLandscape.appPrivacyBottom = @(0*screenScale);
    layoutLandscape.appPrivacyHeight = @(45*screenScale);

    layoutLandscape.sloganLeft = @(0);
    layoutLandscape.sloganRight = @(0);
    layoutLandscape.sloganHeight = @(15*screenScale);
    layoutLandscape.sloganBottom = @(layoutLandscape.appPrivacyBottom.floatValue - layoutLandscape.appPrivacyHeight.floatValue);

    baseUIConfigure.layoutPortrait = layoutPortrait;
    baseUIConfigure.layoutLandscape = layoutLandscape;

    return baseUIConfigure;
}

四.本机认证

1.初始化

**二、SDK使用说明**-->**初始化**

2.本机认证

方法原型

/**
 本机号码校验
 @param complete 校验回调
 */
+ (void)mobileCheckWithLocalPhoneNumberComplete:(YXLComplete)complete;

参数描述

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

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

使用场景

请求示例代码 ObjC:

  1. 导入SDK头文件 #import <YXLoginSDK/YXLoginSDK.h>
[YXLManager mobileCheckWithLocalPhoneNumberComplete:^(YXLCompleteResult * _Nonnull completeResult) {

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

5.添加自定义控件示例

ObjC:

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

    YXLUIConfig * baseUIConfigure = [YXLUIConfig 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{
    //关闭页面
    [YXLKManager finishAuthControllerCompletion:^{
       //如需关闭后present/push新页面,建议在completion回调中执行 
    }];
}

Swift:

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

      let baseUIConfigure = YXLUIConfig()
      //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 hideAuthPageMaskViewWhenUseWindow];
        [YXLManager finishAuthControllerCompletion:nil];
    }]];
    [privacyAlert addAction:[UIAlertAction actionWithTitle:@"同意" style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
        //通知sdk勾选协议
        [YXLManager 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 * authWindowModalPresentationStyle;

状态栏

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

暗黑模式

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

封装动态配色工具类

+(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)yx_login{

    YXLUIConfig *cfg = [YXLUIConfig defaultUIConfig];
    cfg.viewController = self;
    cfg.layoutPortrait = [YXLayout defaultLayout];

    // 开启跟随系统显示模式
    if (@available(iOS 12.0, *)) {
        cfg.authWindowOverrideUserInterfaceStyle = @(UIUserInterfaceStyleUnspecified);
    } else {
        // Fallback on earlier versions
    }

    // 动态适配图片显示
    cfg.logoImage = [UIImage imageNamed:@"apple_icon"];

    // 动态适配背景色、文字颜色
    cfg.loginBtnBgColor = [UIColorTools generateDynamicColor:UIColor.blackColor darkModeColor:UIColor.redColor];
    cfg.loginBtnTextColor = [UIColorTools generateDynamicColor:UIColor.whiteColor darkModeColor:UIColor.yellowColor];
    cfg.customAreaView = ^(UIView * _Nonnull customAreaView) {
        // 授权页面背景色动态配置
        customAreaView.backgroundColor = [UIColorTools generateDynamicColor:UIColor.whiteColor darkModeColor:UIColor.brownColor];
    };

    // 拉起授权页面
    [YXLManager quickAuthLoginWithConfigure:cfg openLoginAuthListener:^(YXLCompleteResult * _Nonnull completeResult) {

    } oneKeyLoginListener:^(YXLCompleteResult * _Nonnull completeResult) {

    }];
}

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

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

9.CheckBox勾选框位置调整

可调整属性

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

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

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

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

checkBoxVerticalAlignmentOffset: 顶部对齐或者中心对齐后的 相对偏移量

勾选框图片位置微调

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

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

checkBox调整.jpg

五.返回码对照

外层错误码

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

外层返回码 返回码描述
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 已过期)
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.cn、mdn.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>
×

反馈成功

非常感谢您的反馈,我们会继续努力做得更好。