基于生活物联网平台的账号及用户SDK,您可以自定义自有品牌App的开放账号OA(Open Account)模块相关的用户界面UI(User Interface),主要包括登录页面、注册页面、密码重置页面等。

前提条件

已完成账号及用户SDK的开发,详细操作,请参见账号及用户SDK

定制项

iOS App的OA UI定制项如下。

App界面图示 可定制内容
图示 修改原生元素
  • 显示手机区号(图示中②)
  • 修改登录和注册按钮的颜色(图示中③)
  • 修改失败提示样式(图示中④)
新增元素
  • 新增控件和单击事件
  • 现有控件增加自定义的事件
  • 新增邮箱登录方式(图示中①)
  • 登录密码输入次数超限后提示找回密码(图示中⑤)

显示手机区号

登录和注册页面中默认不显示手机区号,如果您需要显示手机区号,如+86,请根据以下步骤来操作。

  1. 打开ALBBOpenAccountLoginViewController.xib文件,选择View > Wrapper View > Form View > Username View > Prefix Label
  2. 打开右侧控制面板,选择Prefix Label,并取消选中Hidden复选框。
    此时即可显示手机区号。显示区号
  3. 在命令区域,执行pod Update命令,查看显示效果。
    如果页面中出现内容重叠,请在ALBBOpenAccountLoginViewController.xib中更改相关约束,通过显示和隐藏其他控件来调节显示效果。

修改登录和注册按钮的颜色

App的登录和注册按钮默认为浅灰色,如果您需要修改App登录和注册按钮的颜色,请根据以下步骤来操作。

  1. 注册ALBBOpenAccountLoginViewDelegate相关代理。
  2. 生成并替换按钮颜色的图片。

    您可以通过放置图片的方法来替换按钮颜色,以下为您提供颜色生成图片的扩展方法。

    #pragma mark - ALBBOpenAccountLoginViewDelegate
    - (void)loginViewDidLoad:(ALBBOpenAccountLoginViewController *)viewController {
        // 本示例中按钮的三种状态(正常、高亮、禁用)的颜色一致,您如需不一致,传入不同图片即可
        UIImage *bgImage = [UIImage ims_imageWithColor:[UIColor whiteColor];
        [viewController.submitButton setBackgroundImage:bgImage forState:UIControlStateNormal];
        [viewController.submitButton setBackgroundImage:bgImage forState:UIControlStateHighlighted];
        [viewController.submitButton setBackgroundImage:bgImage forState:UIControlStateDisabled];
    }
    
    // 分类方法
    + (UIImage *)ims_imageWithColor:(UIColor *)color {
      CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
      UIGraphicsBeginImageContext(rect.size);
      CGContextRef context = UIGraphicsGetCurrentContext();
      CGContextSetFillColorWithColor(context, [color CGColor]);
      CGContextFillRect(context, rect);
      UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
      UIGraphicsEndImageContext();
      return image;
    }

修改提示信息样式

当OA模块发生业务错误(如密码错误)时,App会弹出相关提示信息的对话框。如果您需要修改该提示对话框的样式,可以通过设置回调来实现。

[ALBBService(ALBBOpenAccountUIService) setHandleBizErrorCallback:^(NSString *errMsg) {
     UIAlertController *controller = [UIAlertController alertControllerWithTitle:nil message:errMsg preferredStyle:UIAlertControllerStyleAlert];
    [controller addAction:[UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:nil]];
    [[self getCurrentVC] presentViewController:controller animated:true completion:nil];
}];

其中,getCurrentVC方法可参见本文档登录密码输入超限后提示找回密码getCurrentVC的方法。

新增控件和单击事件

当您需要在App中增加新的单击事件时,例如新增一个Button控件的单击事件,您可以根据以下步骤来操作。

  1. ALBBOpenAccountFindPwdViewController.xib中添加一个Button元素。例如,Button标题命名为:我是自定义的Button。
  2. xib目录中添加一个如图所示的Object控件。
    添加object

    添加成功后,如下图所示。

    添加结果显示
  3. 选择File’s Owner,并单击outletCollection对应的加号(+),添加一个控制器,例如命名为Object。
  4. 按住鼠标从如图所示的右下角拖至左上角,关联Object控制器和outletCollection。
    连接

    此处outletCollection是一个NSArray,您也参照以下代码,一次关联多个Object控件。

    @property (nonatomic, strong) IBOutletCollection(NSObject)? NSArray *outletCollection;
  5. 新建一个类,例如命名为CustomController。
    该类继承NSObject,设置Object控制器的Class参数值为CustomController创建类
  6. 在CustomController类中添加一个响应函数,例如命名为IBAction。
    -(IBAction)CustomButtonClick {
        NSLog(@"来自 Custom Button 的Click");
    }
  7. 将新建的Object与新建的Class相关联,如下图所示。
    关联操作
  8. 按住鼠标从如图所示的右下角拖至左上角,关联Button的单击事件和CustomController类,即选择CustomButtonClick函数作为Button单击事件的响应函数。
    关联事件
  9. 单击CustomController对应的Button,验证单击事件。

    如果打印出以下日志则表示单击事件可正常使用。如果您需要单击Button后跳转其他页面,可自行实现。

    日志

现有控件增加自定义事件

当您需要对现有控件增加自定义事件时,例如统计某控件的单击次数等,您可以参考以下示例方法来更改OA内部逻辑并增加自定义事件。

说明 通常不建议您通过Runtime方式来修改非主动暴露的业务逻辑,建议您优先联系技术支持,确认是否有新版本SDK支持该功能,或者提交该功能的需求申请。
//以统计按钮单击次数的逻辑为例
@implementation ALBBOpenAccountSetPwdViewController (aspect)

+ (void)load {
    Method originalMethod = class_getInstanceMethod(self, @selector(submitPassword));
    Method newMethod = class_getInstanceMethod(self, @selector(newSubmitPassword));

    BOOL addMethod = class_addMethod(self, @selector(submitPassword), method_getImplementation(newMethod), method_getTypeEncoding(newMethod));
    if (addMethod) {
        class_replaceMethod(self, @selector(newSubmitPassword), method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, newMethod);
    }
}

- (void)newSubmitPassword {

    [self newSubmitPassword];
   //处理统计次数逻辑

}

@end

新增邮箱登录方式

如果您需要App支持邮箱方式登录,您需要开发邮箱相关的功能,包括邮箱登录(图示中①)、邮箱注册(图示中②)、忘记邮箱密码(图示中③)等。

邮箱登录方式
  1. (可选)从账号及用户SDK的Bundle中拷贝邮箱相关的两个xib文件到工程目录下。

    如果您之前开发过邮箱相关的功能,可直接跳过该步骤的操作。

    邮箱相关的xib文件如下图所示,其中头文件为#import <ALBBOpenAccountCloud/ALBBOpenAccountSDK.h>

    邮箱的xia文件
  2. 在App登录页面增加邮箱登录的方式。

    邮箱登录与手机号登录可以共用同一个登录框,此时您只需要将手机区号隐藏,并在代码中判断输入的内容是邮箱还是手机号即可。如果您需要在UI上区分,可自行实现。

  3. 新增邮箱注册功能。
    1. 确认账号及用户SDK版本。
      pod 'AlicloudALBBOpenAccount', '3.4.0.39' //3.4.0.39及以上版本都支持
    2. 在登录页面增加邮箱注册按钮。
      请参见本文档中新增控件和单击事件来实现。
    3. 调用控制器弹出邮箱注册页面。
      id uiService = ALBBService(ALBBOpenAccountUIService);
      [uiService showEmailRegisterInNavigationController:self.navigationController success:nil failure:nil];
  4. 新增忘记邮箱密码功能。
    通过邮箱方式登录App时,如果忘记了邮箱注册的密码,需要通过邮箱找回密码。
    1. 确认账号及用户SDK版本。
      pod 'AlicloudALBBOpenAccount', '3.4.0.39' //3.4.0.39及以上版本都支持
    2. 在登录页面增加忘记邮箱密码按钮。
      请参见本文档中新增控件和单击事件来实现。
    3. 调用控制器弹出忘记密码页面。
      id<ALBBOpenAccountUIService> uiService = ALBBService(ALBBOpenAccountUIService);
      [uiService showFindPasswordInNavigationController:self.navigationController success:nil failure:nil];

登录密码输入次数超限后提示找回密码

登录App时,如果输入登录密码的次数达到上限,App会限制继续操作,并提示找回密码。登录账号如果是手机号码则跳转至手机忘记密码页面;如果是邮箱则跳转至邮箱忘记密码页面。

登录超次后找回密码

有两种方案可实现登录密码输入次数超限后提示找回密码,您任选一种即可。

说明 如果您同时添加了以下两种方案,则仅生效第二种方案。运行App后,添加功能代码逻辑的方式(即反射+Runtime自定义跳转的方式)会修改SDK中的业务逻辑。
  • 升级SDK

    最新版本账号及用户SDK中已默认支持该能力,您可以通过升级SDK来实现该功能。完成SDK升级后,您无需额外操作。

    pod 'AlicloudALBBOpenAccount', '3.4.0.39'  //3.4.0.39及以上版本都支持
  • 添加该功能代码逻辑

    您还可以通过反射+Runtime自定义跳转的方式来实现该功能。

    // 通过runtime方式做一个方法来替换,将ALBBOpenAccountLoginViewController的私有方法showFindPasswordView转到自己定义的方法findPwdStyleChoose中
    + (void)load {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            Method findPwdMethod = class_getInstanceMethod([self class], @selector(findPwdStyleChoose));
            IMP findPwdNewImp = method_getImplementation(findPwdMethod);
            const char * typeEncodeing = method_getTypeEncoding(findPwdMethod);
            class_replaceMethod([ALBBOpenAccountLoginViewController class], NSSelectorFromString(@"showFindPasswordView"), findPwdNewImp, typeEncodeing);
        });
    }
    
    /**
     显示找回密码方式sheet
     */
    - (void)findPwdStyleChoose {
        __weak typeof(self) weakSelf = self;
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"请选择你要修改的密码类型" message:nil preferredStyle:UIAlertControllerStyleActionSheet];
        UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) {
        }];
    
        UIAlertAction *phoneAction = [UIAlertAction actionWithTitle:@"忘记手机密码?" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
            id<ALBBOpenAccountUIService> uiService = ALBBService(ALBBOpenAccountUIService);
            [uiService showFindPasswordInNavigationController:[weakSelf getCurrentVC].navigationController success:nil failure:nil];
        }];
    
        UIAlertAction *emailAction = [UIAlertAction actionWithTitle:@"忘记邮箱密码?" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
            id<ALBBOpenAccountUIService> uiService = ALBBService(ALBBOpenAccountUIService);
            [uiService showEmailFindPasswordInNavigationController:[self getCurrentVC].navigationController success:nil failure:nil];
        }];
        [alert addAction:cancelAction];
        [alert addAction:phoneAction];
        [alert addAction:emailAction];
        [[self getCurrentVC] presentViewController:alert animated:YES completion:nil];
    }
    
    - (UIViewController *)getCurrentVC {
        UIViewController *result = nil;
    
        UIWindow *window = [[UIApplication sharedApplication] keyWindow];
        if (window.windowLevel != UIWindowLevelNormal) {
            NSArray *windows = [[UIApplication sharedApplication] windows];
            for (UIWindow *temp in windows) {
                if (temp.windowLevel == UIWindowLevelNormal) {
                    window = temp;
                    break;
                }
            }
        }
    
        result = window.rootViewController;
    
        while (result.presentedViewController) {
            result = result.presentedViewController;
        }
    
        if ([result isKindOfClass:[UITabBarController class]]) {
            result = [(UITabBarController *)result selectedViewController];
        }
    
        if ([result isKindOfClass:[UINavigationController class]]) {
            result = [(UINavigationController *)result visibleViewController];
        }
        return result;
    }

更多UI定制

如果您还需定制更多的UI,例如修改更多原生元素,您可以根据以下内容自行实现。

  • 账号及用户SDK开放了所有xib组件,每个xib对应相应的功能页。

    您可以在保证云账号交互逻辑的基础上,通过修改以下任意xib文件,实现改变页面布局、调整控件样式、新增控件等一系列自定义UI的操作。

    xib目录
  • SDK开放了所有ViewController,以及每一个ViewController的UI控件的引用。

    以登录页面对应的UI控件ALBBOpenAccountLoginViewController为例,控件中包括以下元素。

    @interface ALBBOpenAccountLoginViewController : ALBBOpenAccountBaseController
    @property (assign, nonatomic) BOOL isNeedBackButtonHidden;
    
    //预留的外挂引用
    @property (nonatomic, strong) IBOutletCollection(NSObject)  NSArray *outletCollection;
    
    // wrapper
    @property (weak, nonatomic) IBOutlet ALBBOpenAccountWrapperView *wrapperView;
    // form
    @property (weak, nonatomic) IBOutlet NSLayoutConstraint *heightOfFormView;
    
    //locale
    @property (weak, nonatomic) IBOutlet UILabel *prefixLabel;
    @property (weak, nonatomic) IBOutlet UIButton *prefixIcon;
    // username
    @property (weak, nonatomic) IBOutlet UILabel *usernameLabel;
    @property (weak, nonatomic) IBOutlet UITextField *usernameField;
    @property (weak, nonatomic) IBOutlet UIButton *historyButton;
    @property (weak, nonatomic) IBOutlet UITableView *historyView;
    @property (weak, nonatomic) IBOutlet NSLayoutConstraint *heightOfHistoryView;
    // password
    @property (weak, nonatomic) IBOutlet UIView *passwordView;
    @property (weak, nonatomic) IBOutlet UILabel *passwordLabel;
    @property (weak, nonatomic) IBOutlet UITextField *passwordField;
    @property (weak, nonatomic) IBOutlet UIButton *visibleButton;
    
    // control
    @property (weak, nonatomic) IBOutlet UIButton *submitButton;
    
    
    - (IBAction)submitLogin;
    // 前往国家列表
    - (IBAction)prefixNumberChoose:(id)sender;
    
    // sso
    - (IBAction)taobaoSSO:(id)sender;
    #ifdef WECHAT_SSO
    - (IBAction)weChatSSO:(id)sender;
    #endif
    - (IBAction)weiBoSSO:(id)sender;
    - (IBAction)qqSSO:(id)sender;
    
    @property (weak, nonatomic) IBOutlet UIButton *registerLinkBtn;
    @property (weak, nonatomic) IBOutlet UIButton *findPwdLinkBtn;
    - (IBAction)showRegisterView;
    - (IBAction)showFindPasswordView;
    @end
  • SDK开放了每一个ViewController的生命周期回调,便于您定制ViewController的UI控件。

    以ALBBOpenAccountLoginViewDelegate为例,使用方式如下。

    1. 设置一个登录界面的代理。
      [ALBBService(ALBBOpenAccountUIService) setLoginViewDelegate:self];
    2. 设置ALBBOpenAccountLoginViewDelegate代理方式。
      @protocol ALBBOpenAccountLoginViewDelegate <NSObject>
      
      @optional
      - (void)loginViewDidLoad:(ALBBOpenAccountLoginViewController *) viewController;
      - (void)loginViewWillAppear:(ALBBOpenAccountLoginViewController *) viewController;
      - (void)loginViewDidAppear:(ALBBOpenAccountLoginViewController *) viewController;
      - (void)loginViewWillDisappear;
      - (void)loginViewDidDisappear;
      
      - (void)loginViewWillLayoutSubviews:(ALBBOpenAccountLoginViewController *) viewController;
      - (void)loginViewDidLayoutSubviews:(ALBBOpenAccountLoginViewController *) viewController;
      
      @end
    3. 使用代理方法改变内容。
      - (void)loginViewDidLoad:(ALBBOpenAccountLoginViewController *) viewController{
      viewController.navigationItem.rightBarButtonItem=[[UIBarButtonItem alloc]   initWithTitle:@"login" style:UIBarButtonItemStyleDone target:nil action:nil];
      }

如果您还需定制除原生元素以外的内容,可以参考以下信息来实现。

常见问题

  • 问题一

    Q:使用账号及用户SDK时,Crash出现以下提示。

    Crash提示

    A:将ALBBOpenAccountUI.framework中的xib目录放置到主工程目录下即可。

  • 问题二

    Q:账号及用户SDK初始化成功后,单击App登录按钮,没有成功跳转至相应的页面。

    登录跳转失败提示

    A:示例中VC未加入到导航栈,所以推送登录页面会失败。可以用如下方式推出登录页面。

    [uiService presentLoginViewController:self success:^(ALBBOpenAccountSession *currentSession) {
    
            } failure:^(NSError *error) {
    
            }];
  • 问题三

    Q:SDK接口报错,提示:Http load fail。

    A:打开工程的info.plist文件,设置ATS配置即可。

    设置ATS