按照 SDK 是否有界面来进行分类,我们开发的 SDK 无外乎就两类:
- 带有 UI 界面的 SDK,我们开发的大部分 SDK 都是这一类
- 不带有 UI 界面的 SDK,比如 token 计算的 SDK
从接口设计角度,前者比较复杂,本文介绍如何设计 外部APP 页面到 SDK 内部页面的跳转。
1. 跳转分析
iOS 页面呈现,最常用的方式有两类:
- present ViewController
- navigation controller push ViewController
- 使用 UIWindow
设计的时候有以下几个点需要注意:
- 外部 APP 调用页面类型未知,调用 SDK 的有可能是普通的 ViewController,也有可能是 navigation controller ,还有可能是一个 tabbar ViewController,...
- 不能污染外部的页面,退出 SDK 的时候要还原全局设置,比如 status bar 的隐藏和显示状态,status bar 的 UI 风格是浅色还是深色,页面是否常亮,...
2. 跳转的最终方案
在我们的 SDK 中,进入 SDK 页面有两种主流方案:
- 使用 UIWindow 呈现 SDK
- 使用 present 方式,SDK 内部页面用 navigation controller 管理
我们诸多 SDK 中,两种方式都有用到,本文讲解后者。
由于 SDK 中涉及到页面 push,最终选择的方案是在 APP 的调用页面,present navigation controller,将 SDK 的首页设置为 navigation controller 的 root ViewController。
3. 跳转相关细节
SDK 鉴权
先对外部传入的参数进行校验,权限查询,这一步骤通过之后,才能进入下一步骤。
获取 APP 调用 SDK 的 ViewController
基本思路是,获取当前 APP keyWindow 的 rootViewController,然后分类逐层找到最上层的 ViewController。
#pragma mark - private method
// 获取应用当前界面,调用SDK的界面
- (UIViewController*)topViewController {
return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
- (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
NSLog(@"root:UITabBarController");
UITabBarController* tabBarController = (UITabBarController*)rootViewController;
return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
} else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
NSLog(@"root:UINavigationController");
UINavigationController* navigationController = (UINavigationController*)rootViewController;
return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
} else if (rootViewController.presentedViewController) {
NSLog(@"root:rootViewController.presentedViewController");
UIViewController* presentedViewController = rootViewController.presentedViewController;
return [self topViewControllerWithRootViewController:presentedViewController];
} else {
NSLog(@"root:rootViewController");
return rootViewController;
}
}
跳转
通过上面步骤,获取到 rootViewController ,然后在 rootViewController 基础上进行跳转。
WBNavigationController *nav = [[WBNavigationController alloc] initWithRootViewController:[self getTargetViewController]];
[rootViewController presentViewController:nav animated:NO completion:nil];
其中,WBNavigationController 继承自 UINavigationController;
SDK 中包含多个业务,不同业务进入的页面不一样,getTargetViewController
方法获取当次业务对应的目标页面。