需求背景:

1.在一般的项目中,都会有很页面,这样就会出现好多push、present。要找到一个指定页面的跳转,就得去找具体对应代码。查看跳转的参数、这样重复代码较多、而且比较繁琐。如果能够统一管理跳转逻辑、这样就简单多了、只要在同一个地方打断点、查看传递参数就好了。

2.有一个这样的场景、由一个网页的活动页面、跳转至app特定页面、利用一个url、也会简单方便。

3.推送跳转到指定页面

Schemes

我们知道每个app都有自己独立的沙盒、互相独立。这样阻碍了app之间的通信。苹果给我们的通信是通过URL Schemes。只要每个app定义了自己的Schemes,便能实现app之间跳转。苹果系统原生的app、比如打电话tel://等。还有一些第三方的,比如支付宝alipay://。如果在手机同时装了两个Schemes一摸一样的app,我猜想应该是跳转先安装、或者优先采取苹果自己默认的app。所有设置URL Schemes,还是要注重唯一性、这样就不会重复,最好跟bundle identifier一致。

在safari浏览器输入、也会识别到、如下图所示:(图一是alipay://图二为自定义app)



其实Scheme 就是://前面的英文字符。支付宝为alipay、项目中设置如下图:(info中的URL Types中)


跳转的url就是SKJLRoutes://。

路由跳转、就是约定一个url。也就是根据Scheme进行跳转,设置跳转统一逻辑。下面用一个三方JLRouts简单举例说明。

实现如下图的跳转: 页面一跳转到页面一


首先设置好URL Schemes 、暂时就为SKJLRoutes,然后pod引入三方 pod 'JLRoutes' 在appdelegate注册:写入相关代码。

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
    NSLog(@"URL scheme:%@", [url scheme]);
    return [[JLRoutes globalRoutes] routeURL:url];
}
复制代码

约定好push、present跳转url

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    ViewController *viewCtr = [[ViewController alloc]init];
    UINavigationController *na = [[UINavigationController alloc]initWithRootViewController:viewCtr];
    self.window.rootViewController = na;
    
    
    // Push规则
    [[JLRoutes globalRoutes] addRoute:@"/NaPush/:controller" handler:^BOOL(NSDictionary<NSString *,NSString *> * _Nonnull parameters) {
        NSLog(@"parameters==%@",parameters);
        UIViewController *v = [[NSClassFromString(parameters[@"controller"]) alloc] init];
        [self paramToVc:v param:parameters];
        [(UINavigationController*)[self getCurrentVC] pushViewController:v animated:YES];
        return YES;
    }];
    
    // Present规则
    [[JLRoutes globalRoutes] addRoute:@"/Present/:controller" handler:^BOOL(NSDictionary<NSString *,NSString *> * _Nonnull parameters) {
        
        NSLog(@"parameters==%@",parameters);
        UIViewController *v = [[NSClassFromString(parameters[@"controller"]) alloc] init];
        [self paramToVc:v param:parameters];
        [[self getCurrentVC] presentViewController:v animated:YES completion:^{}];
        return YES;
    }];
    
    return YES;
}
复制代码

我们可以看到block中parazmetes为页面传来的参数、controller则为跳转到的控制器。 利用响应者链获取当天控制器、runtime传递参数即可(这部分代码百度而来):

-(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];
        }
    }
}
复制代码

当点击button按钮时,采取url跳转即可:

NSString *customURL = @"SKJLRoute://NaPush/PersonalCenterViewController?userID=20";
 [[UIApplication sharedApplication]openURL:[NSURL URLWithString:customURL] options:@{UIApplicationOpenURLOptionsSourceApplicationKey : @YES} completionHandler:nil];
复制代码

PersonalCenterViewController为第二个控制器、userID为参数。

完整url即为SKJLRoute://NaPush/PersonalCenterViewController?userID=20。 这个和常规的网络跳转链接url很像(类似get),这样我们无论跳转那个页面,不需去找特定的跳转action、只有在appdelegate的block中打印参数即可。

parameters=={
    JLRoutePattern = "/NaPush/:controller";
    JLRouteScheme = JLRoutesGlobalRoutesScheme;
    JLRouteURL = "SKJLRoute://NaPush/PersonalCenterViewController?userID=20";
    controller = PersonalCenterViewController;
    userID = 20;
}
复制代码