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 主类IDaaSDoraemonManager接⼝简介

3.1.1 获取认证实例(sharedInstance)

  /** 
  * 函数名:sharedInstance
  * @param ⽆
  * 返回:获取该类的单例实例对象
  */  
+ (instancetype _Nonnull )sharedInstance;  

3.1.2 获取SDK版本号(getVersion)

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

3.1.3 初始化应用支持的认证服务-(SDKInitWithApplicationExternalId)

/**
 *  安全认证服务初始化
 *  @param applicationExternalId  应用外部ID
 *  @param appKey 应用密钥
 *  @param complete 结果回调到主线程
 */
-(void)SDKInitWithApplicationExternalId:(NSString *)applicationExternalId appKey:(NSString *)appKey complete:(void (^)(NSDictionary *resultDic))complete;

3.1.4 获取应用授权token

此接口需要开发者调用服务端SDK的获取应用授权Token接口,回传给移动端SDK

/** 获取token */
@property (nonatomic,copy) NSDictionary *(^fetchAccessTokenCallBack)(NSString *mobileExtendParamsJson, NSString *mobileExtendParamsJsonSign);

3.1.5 手机号认证:一键登录、本机号码校验(UI自定义)

如何自定义UI, 详情见下方代码示例以及页面UI说明

/**
 *  手机号认证:支持一键登录、本机号码校验
 *  @param userId  用户ID(必填)
 *  @param action  DoraemonAuthTypeVerifyToken、DoraemonAuthTypeLoginToken
 *  @param options  UI界面展示的配置或其他额外配置
 */
-(void)SDKAuthenticateWithUserId:(NSString *)userId action:(DoraemonAuthType)action options:(UIControlOptions *)options complete:(void (^)(NSDictionary *resultDic))complete;

3.1.6 手机号认证:一键登录、本机号码校验(UI默认)

/**
 *  手机号认证-一键登录,快速认证,UI默认
 *  @param userId  用户ID(必填)
 *  @param controller  控制器
 */
-(void)SDKAuthenticatesWithUserId:(NSString *)userId controller:(UIViewController *)controller complete:(void (^)(NSDictionary *resultDic))complete;

4. SDK demo 接入示例

4.1 获取应用授权token示例

 [IDaaSDoraemonManager sharedInstance].fetchAccessTokenCallBack = ^NSDictionary *(NSString *mobileExtendParamsJson, NSString *mobileExtendParamsJsonSign) {
        HKLog(@"mobileExtendParamsJson--- %@",mobileExtendParamsJson);
        HKLog(@"mobileExtendParamsJsonSign--- %@",mobileExtendParamsJsonSign);
    //App服务端调用FetchAccessToken返回的数据库
    NSDictionary *dic = @{
            @"access_token":@"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJiY2Q1NzVjNDJlMjhiZDJmYjM0NGNmNWRiZjY3MWE2Z0xaYnlIYVJZNEwifQ.eyJhdWQiOlsiZG9yYWVtb25fYXBpX3Jlc291cmNlIl0sImdyYW50X3R5cGUiOiJjbGllbnRfY3JlZGVudGlhbHMiLCJfX3BhcmFtZXRlcnNfXyI6eyJfX2NsaWVudCQkYXBwT3NfXyI6ImlPUyIsIl9fY2xpZW50JCR1c2VySWRfXyI6ImxpbmJhb3dlaSIsImdyYW50X3R5cGUiOiJjbGllbnRfY3JlZGVudGlhbHMiLCJfX2NsaWVudCQkYXBwSWRfXyI6ImNvbS5pZHNtYW5hZ2VyLmlkcDQiLCJfX2NsaWVudCQkYXBwbGljYXRpb25FeHRlcm5hbElkX18iOiJBMDAwMDAwMDMiLCJfX2NsaWVudCQkZGV2aWNlVW5pcXVlSWRfXyI6IjBGRTE3NTU2LTg5NTYtNDY4MC1BNkNELUIzMUVBOUM0MDcyOSJ9LCJzY29wZSI6WyJyZWFkIl0sIl9fZXh0ZW5zaW9uc19fIjp7fSwiZXhwIjoxNjM3ODkzODMwLCJqdGkiOiI2NGVmNDY0MS1jMGYwLTQ2MWItOGFjNC00YzNhYmY4OTg3NTYiLCJjbGllbnRfaWQiOiI2NGJjMzhmZGI3NmY4MjE3MDEwMjlmZjRhZjAwNTI5OWdzQ2RtRVM2VXp2In0.D_Fp7nGwC7a-FxGIr9lrPbn37qxRtNwLGSV94KaGnW8",
            @"refresh_token":@"refresh_token",
            @"expires_in":@86399
        };
        return dic;
    };

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

 __weak typeof(self) weakSelf = self;
    TXCustomModel *model = [weakSelf buildCustomModel:NO];
    model.supportedInterfaceOrientations = YES;
    UIControlOptions *options = [[UIControlOptions alloc]init];
    options.controller = weakSelf;
    options.customModel = model;
    options.timeOut = 3.0;
    [[IDaaSDoraemonManager sharedInstance]SDKAuthenticateWithAuthMethod:@"PHONE_VERIFICATION" action:DoraemonAuthTypeLoginToken userId:@"12313" options:options complete:^(NSDictionary *resultDic) {
        NSString *code = [resultDic objectForKey:@"code"];
        if ([PNSCodeLoginControllerPresentSuccess isEqualToString:code]) {
            HKLog(@"弹起授权页成功");
        } else if ([PNSCodeLoginControllerClickCancel isEqualToString:code]) {
            HKLog(@"点击了授权页的返回");
        } else if ([PNSCodeLoginControllerClickChangeBtn isEqualToString:code]) {
            HKLog(@"点击切换其他登录方式按钮");
        } else if ([PNSCodeLoginControllerClickLoginBtn isEqualToString:code]) {
            if ([[resultDic objectForKey:@"isChecked"] boolValue] == YES) {
                HKLog(@"点击了登录按钮,check box选中,SDK内部接着会去获取登录Token");
            } else {
                HKLog(@"点击了登录按钮,check box选中,SDK内部不会去获取登录Token");
            }
        } else if ([PNSCodeLoginControllerClickCheckBoxBtn isEqualToString:code]) {
            HKLog(@"点击check box");
        } else if ([PNSCodeLoginControllerClickProtocol isEqualToString:code]) {
            HKLog(@"点击了协议富文本");
        } else if ([AuthSuccess isEqualToString:code]) {
            //点击登录按钮获取登录Token成功回调
            HKLog(@"token %@",resultDic);
        }
    }];

4.3 授权页全屏模式,横竖屏切换

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; 

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

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;  

4.5 本机号码校验用例

   UIControlOptions *options = [[UIControlOptions alloc]init];
    options.phoneNumber = @"176*****806";
    [[IDaaSDoraemonManager sharedInstance]SDKAuthenticateWithAuthMethod:@"PHONE_VERIFICATION" action:DoraemonAuthTypeVerifyToken userId:@"12313" options:options complete:^(NSDictionary *resultDic) {
        HKLog(@"token %@",resultDic);
    }];java

5. 手机号认证授权页面说明

5.1 全屏授权页面设计规范(支持横竖屏,以竖屏示意)

5.2 弹窗授权页面设计规范(支持横竖屏,以竖屏示意)

iOS竖屏规范

6. iOS常见问题 

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网络下接口请求失败或超时概率稍高。 切换网络时,设置网络不稳定,会较大概率出现超时。

阿里云首页 应用身份服务 (IDaaS) 相关技术圈