iOS SDK 接入

本文是iOS客户端SDK 集成说明文档。

1. 概述

官网下载SDK后进行解压,解压后包含:

  • Demo工程

  • IDaaSDoraemonSDK.framework(安全认证静态库)

  • 具体认证服务SDK

2. 前期准备

2.1 准备工作

如果应用开启了手机号认证服务, 请确保终端设备已经开启4G网络(联通、移动支持3G网络, 但接口耗时会增加),手机号认证授权之后,联通电信可立即使用, 移动需等待10分钟后使用。

2.2 运行demo工程

解压后包含DoraemonDemo工程, 需要将bundleID 、应用密钥、服务密钥(手机号认证)修改为创建应用后获取的值。

2.3 搭建开发环境

应用必须运行在iOS 9.0+平台上。

2.3.1 添加主库

Targets->General->Linked Frameworks and Libraries 中添加主库IDaaSDoraemonSDK.framework

如果应用授权了认证方式,添加额外的认证方式主库:

Targets->General->Linked Frameworks and Libraries 中添加主库ATAuthSDK.framework,

YTXMonitor.framework, YTXOperators.framework,ATAuthSDK.bundle.

2.3.2 Target->BuildSettings设置

Targets->BuildSettings 中 , Other Linker Flags增加-ObjC,⼀定要添加此选项,注意是⼤写C,不是⼩写c,否则⼯程运⾏会crash!

1

3. SDK 调用说明

3.1 SDK 说明

阿里云安全认证服务iOS SDK目前仅提供静态库IDaaSDoraemonSDK.framework形式。

  • 获取SDK版本号

  • 初始化SDK密钥,设置应用密钥, 此密钥是安全认证服务应用密钥。 (如果支持手机号认证服务, 需要在应用详情页面单独复制密钥, 设置到SDK中,如下图:)

2

  • 获取最终请求invoke认证接口参数,调用不同的服务获取到不同认证的信息(手机号认证、IFAA),例如手机号认证是accees_token、phoneNumber, IFAA是Json字符串。

3.2 手机号认证

3.2.1 本机号码登录

开发者需要在APP中集成安全认证服务客户端SDK,并在服务端完成API对接。 iOS支持9.0及以上系统,Android支持4.0及以上。

3

接口调用说明:

  • 调⽤接⼝setAuthSDKInfo:complete,初始化SDK秘钥参数;

  • (可选)调⽤接⼝checkEnvAvailableWithAuthType:complete,检查当前环境是否⽀持本机号码登录;

  • (可选,唤起授权⻚更快)调⽤接⼝accelerateLoginPageWithTimeout:complete,SDK预取号缓存,主要获取⼿机掩码及运营商相关协议信息,调⽤该接⼝可以加快授权⻚唤起的速度,请先进⾏登录态判断后,确保⽤户需要登录再调⽤此接⼝,否则您的功能可能会被限流;

  • 调⽤SDK本机号码登录token接getLoginTokenWithTimeout:controller:model:complete, 弹起授权⻚,点击登录按钮获取⼀键登录token;

  • 调用getMobileExtendParamsJson获取应用签名数据;

  • 调⽤服务端ServiceInvoke接⼝获取最终手机号;

  • (可选)调⽤接⼝cancelLoginVCAnimated,注销授权⻚⾯。

3.2.2 本机号码校验

5

接口调用说明:

  • 调⽤接⼝setAuthSDKInfo:complete,初始化SDK秘钥参数;

  • (可选)调⽤接⼝checkEnvAvailableWithAuthType:complete,检查当前环境是否⽀持本机号码检验;

  • 调⽤SDK 登录token接口getVerifyTokenWithTimeout:complete,获取本机号码校验 token;

  • 调用getMobileExtendParamsJson获取应用签名数据;

  • 调⽤服务端ServiceInvoke接口进⾏本机号码校验。

4. 手机号认证SDK 方法说明

4.1 主类IDaaSDoraemonManager接⼝简介
4.1.1 获取认证实例(sharedInstance)
  /** 
  * 函数名:sharedInstance
  * @param ⽆
  * 返回:获取该类的单例实例对象
  */  
+ (instancetype _Nonnull )sharedInstance;  

4.1.2 获取sdk版本号(getVersion)
/** 
* 函数名:getVersion
* @param ⽆
* 返回:字符串,sdk版本号
*/  
- (NSString *_Nonnull)getVersion;

4.1.3 设置阿里云安全认证服务应用秘钥(setDoraemonSDKInfo)

/**
 *  初始化SDK调用参数,app生命周期内调用一次
 *  @param  base64EncodeKey app对应的秘钥
 *  @param  complete 结果回调到主线程
 */
- (void)setDoraemonSDKInfo:(NSString * _Nonnull)base64EncodeKey complete:(void(^_Nullable)(NSDictionary * _Nonnull resultDic))complete;

4.1.4 获取最终请求invoke认证接口参数
/**
 *  获取最终请求invoke认证接口参数
 *  @param accessToken  调用不同的服务获取到不同认证的信息(号码认证、IFAA),例如号码认证是accees_token, IFAA是Json字符串
 *  @param phoneNumber 手机号码(只有本机号码校验才需要必传)
 *  @param complete 结果回调到主线程
 */
-(void)getMobileExtendParamsJson:(NSString *_Nonnull)accessToken phoneNumber:(NSString *_Nonnull)phoneNumber complete:(void (^_Nullable)(NSDictionary * _Nonnull resultDic))complete

4.2 主类TXCommonHandler接⼝简介
4.2.1 获取手机号认证实例(sharedInstance)
/**     
*函数名:sharedInstance     
*@param 无    
*返回:获取该类的单例实例对象 
*/ 

+(instancetype _Nonnull )sharedInstance;     

4.2.2 设置手机号认证秘钥(setAuthSDKInfo)
/**     
* 函数名:setAuthSDKInfo    
* @brief 初始化SDK调用参数,app生命周期内调用一次    
* @param  方案对应的秘钥,请登录阿里云控制台后,进入认证方案管理,点击秘钥后复制秘钥,建议维护在业务服务端     
* @param complete 结果同步回调,成功时resultDic=@{resultCode:600000, msg:...},其他情况时"resultCode"值请参考PNSReturnCode 
*/

- (void)setAuthSDKInfo:(NSString * _Nonnull)info complete:(void(^_Nullable)(NSDictionary * _Nonnull resultDic))complete; 

4.2.3 检查认证环境(checkEnvAvailableWithComplete)
/**     
* 函数名:checkEnvAvailableWithComplete      
* @brief    检查及准备调用环境,resultDic返回PNSCodeSuccess才能调用下面的功能接口,在初次或切换蜂窝网络之后需要重新调用,一般在一次登录认证流程开始前调一次即可     
* @param    complete 异步结果回调,成功时resultDic=@{resultCode:600000, msg:...},其他情况时"resultCode"值请参考PNSReturnCode,只有成功回调才能保障后续接口调用 
*/ 
- (void)checkEnvAvailableWithComplete:(void (^_Nullable)(NSDictionary * _Nullable resultDic))complete;  

4.2.4 本机号码登录预取号(accelerateLoginPageWithTimeout)
/**      
* 函数名: accelerateLoginPageWithTimeout     
* @brief 加速登录授权页弹起,防止调用 getLoginTokenWithTimeout:controller:model:complete: 等待弹起授权页时间过长      
* @param timeout:接口超时时间,单位s,默认3.0s,值为0.0时采用默认超时时间      
* @param complete 结果异步回调,成功时resultDic=@{resultCode:600000, msg:...},其他情况时"resultCode"值请参考PNSReturnCode 
*/ 
- (void)accelerateLoginPageWithTimeout:(NSTimeInterval)timeout complete:(void (^_Nullable)(NSDictionary * _Nonnull resultDic))complete;   

4.2.5 登录获取token(getLoginTokenWithTimeout)
/**      * 函数名: getLoginNumberWithTimeout      
* @brief    获取登录Token,调用该接口首先会弹起授权页,点击授权页的登录按钮获取Token      * @warning     注意的是,如果前面没有调用 accelerateLoginPageWithTimeout:complete: 接口,该接口内部会自动先帮我们调用,成功后才会弹起授权页,所以有一个明显的等待过程      
* @param    timeout: 接口超时时间,单位s,默认3.0s,值为0.0时采用默认超时时间     
* @param    controller 唤起自定义授权页的容器,内部会对其进行验证,检查是否符合条件     *@param    model自定义授权页面选项,可为nil,采用默认的授权页面,具体请参考TXCustomModel.h文件     
* @param    complete 结果异步回调,"resultDic"里面的"resultCode"值请参考PNSReturnCode,如下:     授权页控件点击事件:700000(点击授权页返回按钮)、700001(点击切换其他登录方式)、     700002(点击登录按钮事件,根据返回字典里面的 "isChecked"字段来区分check box是否被选中,只有被选中的时候        * 内部才会去获取Token)、700003(点击check box事件)、700004(点击协议富文本文字)     接口回调其他事件:600001(授权页唤起成功)、600002(授权页唤起失败)、600000(成功获取Token)、 600011(获取Token失败)、600015(获取Token超时)、600013(运营商维护升级,该功能不可用)、600014(运营商维护升级,该功能已达最大调用次数)..... 
*/

- (void)getLoginTokenWithTimeout:(NSTimeInterval)timeout controller:(UIViewController *_Nonnull)controller model:(TXCustomModel *_Nullable)model complete:(void (^_Nullable)(NSDictionary * _Nonnull resultDic))complete; 

4.2.6 隐藏授权时关闭loading(hideLoginLoading)

/**      
* 函数名:hideLoginLoading      
* @brief 手动隐藏登录获取登录Token之后的等待动画,默认为自动隐藏,当设置 TXCustomModel 实例autoHideLoginLoading = NO 时, 可调用该方法手动隐藏 
*/  
- (void)hideLoginLoading;   

4.2.7 注销登录页面(cancelLoginVCAnimated)
/**      
* 函数名:cancelLoginVCAnimated      
* @param flag:是否添加动画      
* @param complete成功返回 
*/ 
-(void)cancelLoginVCAnimated:(BOOL)flag complete:(void (^_Nullable)  (void))complete;  

4.2.8 获取日志埋点相关控制对象(getReporter)
/** 
* 函数名:getReporter 
* @brief 获取⽇志埋点相关控制对象 
*/ 

- (PNSReporter * _Nonnull)getReporter;     
4.2.9 加速获取本机号码校验token(accelerateVerifyWithTimeout)
/** 
* 函数名:accelerateVerifyWithTimeout 
* @param timeout:接⼝超时时间,单位s,默认3.0s,值为0.0时采⽤默认超时时间 
* @param complete 结果异步回调到主线程,成功时resultDic=@{resultCode:600000, token:..., msg:...},其他情况时"resultCode"值请参考PNSReturnCode 
*/  

- (void)accelerateVerifyWithTimeout:(NSTimeInterval)timeout complete:(void (^_Nullable)(NSDictionary * _Nonnull resultDic))complete;

4.2.10 本机号码校验获取token(getVerifyTokenWithTimeout)
/** 
* 函数名:getVerifyTokenWithTimeout 
* @param timeout:接⼝超时时间,单位s,默认3.0s,值为0.0时采⽤默认超时时间 
* @param complete 结果异步回调到主线程,成功时resultDic=@{resultCode:600000, token:..., msg:...},其他 情时"resultCode"值请参考PNSReturnCode 
*/  

- (void)getVerifyTokenWithTimeout:(NSTimeInterval)timeout complete:(void (^_Nullable)(NSDictionary * _Nonnull resultDic))complete;   

4.3 主类TXCommonUtils接⼝简介
4.3.1 判断设备蜂窝网络是否开启(checkDeviceCellularDataEnable)

/**      
* 函数名:checkDeviceCellularDataEnable 
*/ 

+ (BOOL)checkDeviceCellularDataEnable;             

4.3.2 判断当前上网卡是否是中国联通(isChinaUnicom)
/**      
* 函数名:isChinaUnicom 
*/ 

+ (BOOL)isChinaUnicom;   

4.3.3 判断当前上网卡是否是中国移动(isChinaMobile)
/**      
* 函数名:isChinaMobile 
*/ 

+ (BOOL)isChinaMobile;             

4.3.4 判断当前上网卡是否是中国电信(isChinaTelecom)
/**      
* 函数名:isChinaTelecom 
*/ 

+ (BOOL)isChinaTelecom;             

4.3.5 获取当前上网卡网络名称(getCurrentMobileNetworkName)

/**      
* 函数名:getCurrentMobileNetworkName      
* @return ChinaMobile,ChinaUnicom,ChinaTelecom,OtherChinaMobileNetwork,NoChinaMobileNetwork */ 

+ (NSString *)getCurrentMobileNetworkName;  

4.3.6 获取当前上网卡运营商名称(getCurrentCarrierName)
/**      
* 函数名:getCurrentCarrierName      
* @return:中国移动,中国联通,中国电信等 
*/ 

+ (NSString *)getCurrentCarrierName; 

4.3.7 获取当前上网网络类型(getNetworktype)
/**      
* 函数名:getNetworktype      
* @return:WiFi,4G,3G,2G,NoInternet等 
*/ 

+ (NSString *)getNetworktype;   

4.3.8 判断设备是否有

/**      
* 函数名:simSupportedIsOK      
* @return: 
*/ 

+ (BOOL)simSupportedIsOK;             

4.3.9 判断wwan是否开启(isWWANOpen)
/**      
* 函数名:isWWANOpen      
* @breif:判断wwan是否开启(通过p0网卡判断,无wifi或有wifi情况下都能检测到) 
*/ 

+ (BOOL)isWWANOpen;             
4.3.10 判断无wifi下wwan是否开启(reachableViaWWAN)
/**  
* 函数名:reachableViaWWAN  
* @return:  
*/ 

+ (BOOL)reachableViaWWAN;             

4.3.11 获取设备当前网络私网IP地址(getMobilePrivateIPAddress)
/**     
* 函数名:getMobilePrivateIPAddress     
* @return: 
*/ 

+ (NSString *)getMobilePrivateIPAddress;             

4.4 本机号码登录获取手机号

当成功获取到getLoginTokenWithTimeout并成功获取token后,将token传递至getMobileExtendParamsJson接口,将返回的结果传递至服务器,服务端携带token调用阿里云的ServiceInvoke接口即可进行最终的取号操作。

4.5 本机号码校验结果

当成功获取到getVerifyTokenWithTimeout并成功获取token后,将token与输入的手机号传递至getMobileExtendParamsJson接口,将返回的结果传递至服务器,服务端携带token调用阿里云的ServiceInvoke接口即可进行最终的校验操作。

5. SDK demo 接入示例

5.1 本机号码登录唤起授权页

//1. 设置SDK参数,app⽣命周期内调⽤⼀次即可  
//设置应用密钥
[[IDaaSDoraemonManager sharedInstance] setDoraemonSDKInfo:@"应用密钥" complete:^(NSDictionary * _Nonnull resultDic) {}];
NSString *info = @"客户的秘钥串"; 
__weak typeof(self) weakSelf = self;  
//设置号码认证密钥 
[[TXCommonHandler sharedInstance] setAuthSDKInfo:info complete:^(NSD ictionary *     _Nonnull resultDic) {    
    [weakSelf showResult:resultDic];  }];  
//2. 检测当前环境是否⽀持本机号码登录,⽀不⽀持提前知道  
__block BOOL support = YES;  
[[TXCommonHandler sharedInstance] checkEnvAvailableWithAuthType:PNSA     uthTypeLoginToken complete:^(NSDictionary * _Nullable resultDic) {     
    support = [PNSCodeSuccess isEqualToString:[resultDic objectForKe y:@"resultCode"]];  
}]; 
//3. 开始本机号码登录流程  
//3.1 调⽤加速授权⻚弹起接⼝,提前获取必要参数,为后⾯弹起授权⻚加速 
[[TXCommonHandler sharedInstance] accelerateLoginPageWithTimeout:tim eout     complete:^(NSDictionary * _Nonnull resultDic) {    
    if ([PNSCodeSuccess isEqualToString:[resultDic objectForKey:@"re sultCode"]] == NO)     {      
        [ProgressHUD showError:@"取号,加速授权⻚弹起失败"];        
        [weakSelf showResult:resultDic];       
        return ;     
    }    
    //3.2 调⽤获取登录Token接⼝,可以⽴⻢弹起授权⻚,model的创建需要放在主线程     [ProgressHUD dismiss];    
    [[TXCommonHandler sharedInstance] getLoginTokenWithTimeout:timeo ut     controller:weakSelf model:model complete:^(NSDictionary * _Nonnul l resultDic)     {         
        NSString *code = [resultDic objectForKey:@"resultCode"];       
        if ([PNSCodeLoginControllerPresentSuccess isEqualToString:co de]) {
            [ProgressHUD showSuccess:@"弹起授权⻚成功"];        
        } else if ([PNSCodeLoginControllerClickCancel isEqualToStrin g:code]) {             [ProgressHUD showSuccess:@"点击了授权⻚的返回"];        
        } else if ([PNSCodeLoginControllerClickChangeBtn isEqualToSt ring:code]) {
         [ProgressHUD showSuccess:@"点击切换其他登录⽅式按钮"];         
        } else if ([PNSCodeLoginControllerClickLoginBtn isEqualToStr ing:code]) { 
            if ([[resultDic objectForKey:@"isChecked"] boolValue] == YES) {  
                [ProgressHUD showSuccess:@"点击了登录按钮,check box选 中,SDK内部接着    会去获取登录Token"];             
            } else {                 
                [ProgressHUD showSuccess:@"点击了登录按钮,check box选 中,SDK内部不会    去获取登录Token"];             
            }         
        } else if ([PNSCodeLoginControllerClickCheckBoxBtn isEqualTo String:code]) {             
            [ProgressHUD showSuccess:@"点击check box"];       
        } else if ([PNSCodeLoginControllerClickProtocol isEqualToStr ing:code]) {
            [ProgressHUD showSuccess:@"点击了协议富⽂本"];     
        } else if ([PNSCodeSuccess isEqualToString:code]) { 
            //点击登录按钮获取登录Token成功回调          
            NSString *token = [resultDic objectForKey:@"token"];        
            //下⾯获取应用签名数据,之后请求服务端认证接口            
           [idaasDoraemonManager getMobileExtendParamsJson:token phoneNumber:@"" complete:^(NSDictionary * _Nonnull resultDic) {
    NSlog(@"%@",resultDic);
      }];       
        } else {     
            [ProgressHUD showError:@"获取登录Token失败"];  
        }        
        [weakSelf showResult:resultDic];  
    }]; 
}];

5.2 授权页全屏模式,横竖屏切换
TXCustomModel *model = [[TXCustomModel alloc] init];    
model.navColor = UIColor.orangeColor;     
model.navTitle = [[NSAttributedString alloc] initWithString:@"本机号码登录(全屏)" attributes:@{NSForegroundColorAttributeName : UIColor.whiteColor,NSFontAttributeName : [UIFont systemFontOfSize:20.0]}];    
//model.navIsHidden = NO;    
model.navBackImage = [UIImage imageNamed:@"icon_nav_back_light"];     //model.hideNavBackItem = NO;     
UIButton *rightBtn = [UIButton buttonWithType:UIButtonTypeSystem];     
[rightBtn setTitle:@"更多" forState:UIControlStateNormal];    
model.navMoreView = rightBtn;     
model.privacyNavColor = UIColor.orangeColor;     
model.privacyNavBackImage = [UIImage imageNamed:@"icon_nav_back_light"];
model.privacyNavTitleFont = [UIFont systemFontOfSize:20.0];   
model.privacyNavTitleColor = UIColor.whiteColor;     
model.logoImage = [UIImage imageNamed:@"taobao"];    
//model.logoIsHidden = NO;     
//model.sloganIsHidden = NO;     
model.sloganText = [[NSAttributedString alloc] initWithString:@"本机号码登录slogan文案" attributes:@{NSForegroundColorAttributeName : UIColor.orangeColor,NSFontAttributeName : [UIFont systemFontOfSize:16.0]}];  
model.numberColor = UIColor.orangeColor;     
model.numberFont = [UIFont systemFontOfSize:30.0];     
model.loginBtnText = [[NSAttributedString alloc] initWithString:@"本机号码登录" attributes:@{NSForegroundColorAttributeName : UIColor.whiteColor,NSFontAttributeName : [UIFont systemFontOfSize:20.0]}]; 
//model.autoHideLoginLoading = NO;     
//model.privacyOne = @[@"《隐私1》",@"https://www.taobao.com/"]; 
//model.privacyTwo = @[@"《隐私2》",@"https://www.taobao.com/"];  
model.privacyColors = @[UIColor.lightGrayColor, UIColor.orangeColor];
model.privacyAlignment = NSTextAlignmentCenter;     
model.privacyFont = [UIFont fontWithName:@"PingFangSC-Regular" size:13.0]; 
model.privacyOperatorPreText = @"《";     
model.privacyOperatorSufText = @"》";     
//model.checkBoxIsHidden = NO;     
model.checkBoxWH = 17.0;     
model.changeBtnTitle = [[NSAttributedString alloc] initWithString:@"切换到其他方式" attributes:@{NSForegroundColorAttributeName : UIColor.orangeColor,NSFontAttributeName : [UIFont systemFontOfSize:18.0]}];  
//model.changeBtnIsHidden = NO;    
//model.prefersStatusBarHidden = NO;    
model.preferredStatusBarStyle = UIStatusBarStyleLightContent;  
//model.presentDirection = PNSPresentationDirectionBottom;   
//授权页默认控件布局调整     
//model.navBackButtonFrameBlock =    
//model.navTitleFrameBlock =     
model.navMoreViewFrameBlock = ^CGRect(CGSize screenSize, CGSize superViewSize, CGRect frame) {         
    CGFloat width = superViewSize.height;  
    CGFloat height = width;         
    return CGRectMake(superViewSize.width - 15 - width, 0, width, height); 
};     
model.loginBtnFrameBlock = ^CGRect(CGSize screenSize, CGSize superViewSize, CGRect frame) {        
    if ([self isHorizontal:screenSize]) { 
        frame.origin.y = 20;           
        return frame;        
    }        
    return frame;  
};     
model.sloganFrameBlock = ^CGRect(CGSize screenSize, CGSize superViewSize, CGRect frame) {         
    if ([self isHorizontal:screenSize]) {  
        return CGRectZero; //横屏时模拟隐藏该控件     
    } else {          
        return CGRectMake(0, 140, superViewSize.width, frame.size.height);  
    }     
};    
model.numberFrameBlock = ^CGRect(CGSize screenSize, CGSize superViewSize, CGRect frame) {        
    if ([self isHorizontal:screenSize]) { 
        frame.origin.y = 140;        
    }        
    return frame;  
};     
model.loginBtnFrameBlock = ^CGRect(CGSize screenSize, CGSize superViewSize, CGRect frame) {         
    if ([self isHorizontal:screenSize]) { 
        frame.origin.y = 185;      
    }         
    return frame;     
};     
model.changeBtnFrameBlock = ^CGRect(CGSize screenSize, CGSize superViewSize, CGRect frame) {        
    if ([self isHorizontal:screenSize]) {
        return CGRectZero; //横屏时模拟隐藏该控件    
    } else {            
        return CGRectMake(10, frame.origin.y, superViewSize.width - 20, 30);
    }     
};     
//model.privacyFrameBlock =    
//添加自定义控件并对自定义控件进行布局    
__block UIButton *customBtn = [UIButton buttonWithType:UIButtonTypeCustom];  
[customBtn setTitle:@"这是一个自定义控件" forState:UIControlStateNormal]; 
[customBtn setBackgroundColor:UIColor.redColor];  
customBtn.frame = CGRectMake(0, 0, 230, 40);    
model.customViewBlock = ^(UIView * _Nonnull superCustomView) { 
    [superCustomView addSubview:customBtn];    
};     
model.customViewLayoutBlock = ^(CGSize screenSize, CGRect contentViewFrame, CGRect navFrame, CGRect titleBarFrame, CGRect logoFrame, CGRect sloganFrame, CGRect numberFrame, CGRect loginFrame, CGRect changeBtnFrame, CGRect privacyFrame) { 
    CGRect frame = customBtn.frame;
    frame.origin.x = (contentViewFrame.size.width - frame.size.width) * 0.5; 
    frame.origin.y = CGRectGetMinY(privacyFrame) - frame.size.height - 20;    
    frame.size.width = contentViewFrame.size.width - frame.origin.x * 2;    
    customBtn.frame = frame;     }; 
// 横竖屏切换 
model.supportedInterfaceOrientations = UIInterfaceOrientationMaskAllButUpsideDown;
// 仅支持竖屏 
model.supportedInterfaceOrientations = UIInterfaceOrientationMaskPortrait; 
// 仅支持横屏 
model.supportedInterfaceOrientations = UIInterfaceOrientationMaskLandscape; 

5.3 授权页弹窗模式,支持横竖屏切换

TXCustomModel *model = [[TXCustomModel alloc] init]; 
model.alertCornerRadiusArray = @[@10, @10, @10, @10]; 
//model.alertCloseItemIsHidden = YES;    
model.alertTitleBarColor = UIColor.orangeColor;     
model.alertTitle = [[NSAttributedString alloc] initWithString:@"本机号码登录(弹窗)" attributes:@{NSForegroundColorAttributeName : UIColor.whiteColor, NSFontAttributeName : [UIFont systemFontOfSize:20.0]}];     
model.alertCloseImage = [UIImage imageNamed:@"icon_close_light"];    
model.privacyNavColor = UIColor.orangeColor;   
model.privacyNavBackImage = [UIImage imageNamed:@"icon_nav_back_light"];     
model.privacyNavTitleFont = [UIFont systemFontOfSize:20.0];     
model.privacyNavTitleColor = UIColor.whiteColor;    
model.logoImage = [UIImage imageNamed:@"taobao"];     
//model.logoIsHidden = NO;     
//model.sloganIsHidden = NO;    
model.sloganText = [[NSAttributedString alloc] initWithString:@"本机号码登录slogan文案" attributes:@{NSForegroundColorAttributeName : UIColor.orangeColor,NSFontAttributeName : [UIFont systemFontOfSize:16.0]}];    
model.numberColor = UIColor.orangeColor;     
model.numberFont = [UIFont systemFontOfSize:30.0];     
model.loginBtnText = [[NSAttributedString alloc] initWithString:@"本机号码登录" attributes:@{NSForegroundColorAttributeName : UIColor.whiteColor, NSFontAttributeName : [UIFont systemFontOfSize:20.0]}];     
//model.autoHideLoginLoading = NO;     
//model.privacyOne = @[@"《隐私1》",@"https://www.taobao.com/"];     //model.privacyTwo = @[@"《隐私2》",@"https://www.taobao.com/"];     
model.privacyColors = @[UIColor.lightGrayColor, UIColor.orangeColor];     model.privacyAlignment = NSTextAlignmentCenter;    
model.privacyFont = [UIFont fontWithName:@"PingFangSC-Regular" size:13.0];     
model.privacyOperatorPreText = @"《";     
model.privacyOperatorSufText = @"》";    
//model.checkBoxIsHidden = NO;     
model.checkBoxWH = 17.0;     
model.changeBtnTitle = [[NSAttributedString alloc] initWithString:@"切换到其他方式" attributes:@{NSForegroundColorAttributeName : UIColor.orangeColor,NSFontAttributeName : [UIFont systemFontOfSize:18.0]}];     //model.changeBtnIsHidden = NO;     
//model.prefersStatusBarHidden = NO;     
//model.preferredStatusBarStyle = UIStatusBarStyleDefault;     
//model.presentDirection = PNSPresentationDirectionBottom;     
CGFloat ratio = MAX(TX_SCREEN_WIDTH, TX_SCREEN_HEIGHT) / 667.0;     
//实现该block,并且返回的frame的x或y大于0,则认为是弹窗谈起授权页    
model.contentViewFrameBlock = ^CGRect(CGSize screenSize, CGSize contentSize, CGRect frame) {         
CGFloat alertX = 0;         
CGFloat alertY = 0;         
CGFloat alertWidth = 0;         
CGFloat alertHeight = 0;         
if ([self isHorizontal:screenSize]) {            
    alertX = ratio * TX_Alert_Horizontal_Default_Left_Padding;                
    alertWidth = screenSize.width - alertX * 2;             
    alertY = (screenSize.height - alertWidth * 0.5) * 0.5;             
    alertHeight = screenSize.height - 2 * alertY;         
} else {             
    alertX = TX_Alert_Default_Left_Padding * ratio;             
    alertWidth = screenSize.width - alertX * 2;             
    alertY = TX_Alert_Default_Top_Padding * ratio;             
    alertHeight = screenSize.height - alertY * 2;         
}         
return CGRectMake(alertX, alertY, alertWidth, alertHeight);     
};     
//授权页默认控件布局调整     
//model.alertTitleBarFrameBlock =     
//model.alertTitleFrameBlock =     
//model.alertCloseItemFrameBlock =     
model.logoFrameBlock = ^CGRect(CGSize screenSize, CGSize superViewSize, CGRect frame) {   
    if ([self isHorizontal:screenSize]) { 
        return CGRectZero; 
        //横屏时模拟隐藏该控件        
    } else {            
        frame.origin.y = 10;            
        return frame;         
    }     
};     
model.sloganFrameBlock = ^CGRect(CGSize screenSize, CGSize superViewSize, CGRect frame) {        
    if ([self isHorizontal:screenSize]) { 
        return CGRectZero; 
        //横屏时模拟隐藏该控件    
    } else {            
        frame.origin.y = 110;         
        return frame;        
    }    
};     
model.numberFrameBlock = ^CGRect(CGSize screenSize, CGSize superViewSize, CGRect frame) {        
    if ([self isHorizontal:screenSize]) { 
        frame.origin.y = 20;            
        frame.origin.x = (superViewSize.width * 0.5 - frame.size.width) * 0.5 + 18.0;         
    } else {    
        frame.origin.y = 140;       
    }         
    return frame;     
};     
model.loginBtnFrameBlock = ^CGRect(CGSize screenSize, CGSize superViewSize, CGRect frame) {        
    if ([self isHorizontal:screenSize]) {  
        frame.origin.y = 60;            
        frame.size.width = superViewSize.width * 0.5; 
        //登录按钮最小宽度是其父视图的一半,再小就不生效了       
    } else {             
        frame.origin.y = 180;         
    }        
    return frame;    
};     
model.changeBtnFrameBlock = ^CGRect(CGSize screenSize, CGSize superViewSize, CGRect frame) {         
    if ([self isHorizontal:screenSize]) {
        return CGRectZero; //横屏时模拟隐藏该控件   
    } else {  
        return CGRectMake(10, 240, superViewSize.width - 20, 30);
    }     
};     
//model.privacyFrameBlock =    
//添加自定义控件并对自定义控件进行布局    
__block UIButton *customBtn = [UIButton buttonWithType:UIButtonTypeCustom]; 
[customBtn setTitle:@"这是一个自定义控件" forState:UIControlStateNormal];  
[customBtn setBackgroundColor:UIColor.redColor];     
model.customViewBlock = ^(UIView * _Nonnull superCustomView) {          [superCustomView addSubview:customBtn];     };     
model.customViewLayoutBlock = ^(CGSize screenSize, CGRect contentViewFrame, CGRect navFrame, CGRect titleBarFrame, CGRect logoFrame, CGRect sloganFrame, CGRect numberFrame, CGRect loginFrame, CGRect changeBtnFrame, CGRect privacyFrame) {        
    CGFloat padding = 15;        
    CGFloat x = 0;         
    CGFloat y = 0;         
    CGFloat width = 0;        
    CGFloat height = 0;         
    if ([self isHorizontal:screenSize]) {   
        x = CGRectGetMaxX(loginFrame) + padding;   
        y = padding;             
        width = contentViewFrame.size.width - x - padding;  
        height = CGRectGetMinY(privacyFrame) - y - padding;       
    } else {            
        x = padding;        
        y = MAX(CGRectGetMaxY(changeBtnFrame), CGRectGetMaxY(loginFrame)) + padding;             
        width = contentViewFrame.size.width - 2 * x;            
        height = CGRectGetMinY(privacyFrame) - y - padding;     
    }         
    customBtn.frame = CGRectMake(x, y, width, height);  
}; 
// 横竖屏切换 
model.supportedInterfaceOrientations =UIInterfaceOrientationMaskAllButUpsideDown; 
// 仅支持竖屏 
model.supportedInterfaceOrientations = UIInterfaceOrientationMaskPortrait; 
// 仅支持横屏 
model.supportedInterfaceOrientations = UIInterfaceOrientationMaskLandscape;  

5.4 本机号码校验用例
//1. 设置SDK参数,app⽣命周期内调⽤⼀次即可 
//设置应用密钥
[[IDaaSDoraemonManager sharedInstance] setDoraemonSDKInfo:@"应用密钥" complete:^(NSDictionary * _Nonnull resultDic) {}];
NSString *info = @"客户的秘钥串"; 
__weak typeof(self) weakSelf = self;  
//设置号码认证密钥  
[[TXCommonHandler sharedInstance] setAuthSDKInfo:info complete:^(NSD ictionary * _Nonnull resultDic) { [weakSelf showResult:resultDic]; }]; 
//2. 检测当前环境是否⽀持本级号码校验,⽀不⽀持提前知道  
__block BOOL support = YES;  
[[TXCommonHandler sharedInstance] checkEnvAvailableWithAuthType:PNSA uthTypeVerifyToken complete:^(NSDictionary * _Nullable resultDic) {    
    support = [PNSCodeSuccess isEqualToString:[resultDic objectForKe y:@"resultCode"]];  
}];  
if (self.tf_phoneNumber.text.length == 0) {     
    [ProgressHUD showError:@"请先输⼊⼿机号码"];     
    return;  
}  
float timeout = self.tf_timeout.text.floatValue; 
[ProgressHUD show:@"请稍等..." Interaction:YES]; 
__weak typeof(self) weakSelf = self;  
//3. 获取 VerifyToken  

[[TXCommonHandler sharedInstance] getVerifyTokenWithTimeout:timeout complete:^(NSDictionary * _Nonnull resultDic) {     
    if ([PNSCodeSuccess isEqualToString:[resultDic objectForKey:@"re sultCode"]] == NO) {        
        [ProgressHUD showError:@"获取 VerifyToken失败"];         
        [weakSelf showResult:resultDic];         
        return ;     
    }     
    //3. 去服务器验证 VerifyToken 
    
    [weakSelf showResult:resultDic];    
    NSString *token = [resultDic objectForKey:@"token"];  
    
   [idaasDoraemonManager getMobileExtendParamsJson:token phoneNumber:self.tf_phoneNumber.text complete:^(NSDictionary * _Nonnull resultDic) {
   NSlog(@"%@",resultDic);
    }];
         

FAQ

1. 初始化接口checkEnvAvailableWithComplete一直返回NO

排查顺序:1、手机sim卡是否被激活或欠费;2、手机设备蜂窝数据是否开启;3、App的网络权限是否开启;4、设备是否有代理;用户开启VPN后一键登录的时候可能联通号码出现源IP错误,或者电信号码出现800008错误,移动号码出现103111错误,请关闭VPN之后或者打开飞行模式再关闭之后再重试。5、云控制台上是否创建了方案号;6、创建方案号中的bundleId一定要与项目中使用的保持一致;7,设备时间设置是否非标准,不能修改手机时间戳提前或延期;8,是否调用了setAuthSDKInfo接口;9,最后再提供bundleId给我们进行查询日志。

2. 移动卡出现crash【[UAReachability reachableType]: unrecognized selector sent to instance】

在主工程中Project -> Edit Active Target -> Build Setting -> Other Linker Flags中添加-all_load标记,前提也要添加-ObjC,即两者都要添加。

3. 登录token存在失败吗?

肯定存在的,如果是偶现,可以理解,因为比如网络波动导致网关断开、网络不可用、供应商服务端异常,业务方服务端异常等因素有关;如果是持续出现,一般需要运营商协助排查。

4. 本机号码登录服务一般只4G或者4G+Wifi情况下,如果是3G、2G会怎么样?

中国移动支持2G/3G/4G、中国联通支持3G/4G、中国电信支持4G,但2G和3G网络下接口请求失败或超时概率稍高。

5. 经常超时怎么办?

首先确认sim卡不欠费,再确认手机网络是否正常,通过Safari打开某个网址验证为准。其次确认超时时间是否设置正确,单位是s。 2G和3G网络下接口请求失败或超时概率稍高。 切换网络时,设置网络不稳定,会较大概率出现超时。