ios APP跳转发生在这么几个地方:
1.APP内部UIViewController之间。
2.APP跳转其他APP。
3.从网页,推送或者其他APP跳转到APP指定页面。
//1.APP内部UIViewController之间
ViewController2 * vc = [[ViewController2 alloc]init];
[self.navigationController pushViewController:vc animated:YES];
//或者
//[self presentViewController:vc animated:YES completion:nil];
//2.APP跳转其他APP
NSURL * url = [NSURL URLWithString:@"TestJLRouter2://abc"];
if([[UIApplication sharedApplication]canOpenURL:url])
{
[[UIApplication sharedApplication] openURL:url options:[NSDictionary dictionary] completionHandler:^(BOOL success) {
}];
}
//3.AppDelegate的代理方法会被调用,可以根据url进行匹配
-(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
我们会发现代码分散且不统一,我们想到使用Mediator模式统一处理这些跳转逻辑,github上比较优秀的作品是JLRoutes和HHRouter。
他们的思路基本上都是做一个Map,注册控制器到Map,并通过字符串匹配,进行跳转。
使用HHRouter
//在AppDelegate中注册控制器
[[HHRouter shared]map:@"ViewController" toControllerClass:ViewController.class];
//1.APP内部UIViewController之间,有点在于不需要#import"ViewController"
UIViewController * vc = [[HHRouter shared]matchController:@"ViewController"];
[self.navigationController pushViewController:vc animated:YES];
//2.同传统方法
使用JLRoutes
//在AppDelegate中注册控制器并重写openURL
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[JLRoutes globalRoutes]addRoute:@"/NaviPush/:controller/:param" handler:^BOOL(NSDictionary<NSString *,id> * _Nonnull parameters) {
NSLog(@"parameters:%@",parameters);
UIViewController *currentVc = [self currentViewController];
UIViewController *v = [[NSClassFromString(parameters[@"controller"]) alloc] init];
[self paramToVc:v param:parameters];
[currentVc.navigationController pushViewController:v animated:YES];
return YES;
}];
}
//在该代理方法中做统一处理,不管是内部跳转还是外部跳过来,都会来到该代理
-(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
NSLog(@"url:%@-%@",url,self.class);
return [JLRoutes routeURL:url];
}
-(UIViewController *)currentViewController{
UIViewController * currVC = nil;
UIViewController * Rootvc = self.window.rootViewController ;
do {
if ([Rootvc isKindOfClass:[UINavigationController class]]) {
UINavigationController * nav = (UINavigationController *)Rootvc;
UIViewController * v = [nav.viewControllers lastObject];
currVC = v;
Rootvc = v.presentedViewController;
continue;
}else if([Rootvc isKindOfClass:[UITabBarController class]]){
UITabBarController * tabVC = (UITabBarController *)Rootvc;
currVC = tabVC;
Rootvc = [tabVC.viewControllers objectAtIndex:tabVC.selectedIndex];
continue;
}
} while (Rootvc!=nil);
return currVC;
}
-(void)paramToVc:(UIViewController *) v param:(NSDictionary<NSString *,NSString *> *)parameters{
// runtime将参数传递至需要跳转的控制器
unsigned int outCount = 0;
objc_property_t * properties = class_copyPropertyList(v.class , &outCount);
for (int i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
NSString *key = [NSString stringWithUTF8String:property_getName(property)];
NSString *param = parameters[key];
if (param != nil) {
[v setValue:param forKey:key];
}
}
}
//1.APP内部UIViewController之间并传递参数
NSString *customURL =[NSString stringWithFormat:@"TestRouter://NaviPush/ViewController3/zsy?age=22"];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:customURL] options:@{} completionHandler:nil];
//2.同传统方法