KYRouter 1.0.1

KYRouter 1.0.1

测试已测试
语言语言 Obj-CObjective C
许可证 MIT
发布最近发布2017年8月

kingly09 维护。



KYRouter 1.0.1

一个高效、灵活、易用的 iOS URL Router

前言

随着用户需求的不断增多,对App的用户体验要求也越来越高。为了更好地应对这些需求,开发人员从软件工程的角度出发,将App架构从简单的MVC转变为MVVM,VIPER等复杂的架构。更换适合业务的架构是为了后期更好地维护项目。

但是用户仍然不满意,继续对开发人员提出了更高要求,不仅需要高质量的用户体验,还要求快速迭代,最好一天能推出一个新功能,且用户要求在不更新App的情况下就能体验到新功能。为了满足用户需求,开发人员就采用了H5、ReactNative、Weex等技术对现有项目进行改造。项目架构也随之变得更加复杂,纵向上进行分层,如网络层、UI layer层、数据持久层。每层横向上也会根据业务进行组件化。尽管这样做提高了开发效率,也便于维护,但如何解耦各层,如何解耦各个界面和组件,如何降低组件之间的耦合度,如何使整个系统在面对复杂情况时仍能保持“高内聚、低耦合”的特点?这一系列问题都摆在了开发人员面前,亟待解决。

App亟待解决的问题

  • 3D-Touch功能或点击推送消息,要求从外部跳转到App内部一个很深层次的界面。

例如微信的3D-Touch可以直接跳转到“我的二维码”,“我的二维码”界面位于第三级界面之内。或者更进一步,如果产品需求更加变态,要求跳转到第十层界面,如何处理?

  • 自家的多个App之间如何相互跳转?

如果自己有几个App,相互间也需要相互跳转,怎么办?

  • 如何解除App组件之间和页面之间的耦合性?

随着项目越来越复杂,各组件、各页面之间的跳转逻辑关联性越来越多,如何优雅地解除这些组件和页面之间的耦合性?

  • 如何实现iOS和Android两端页面跳转逻辑的统一?甚至如何实现三端请求资源的统一方式?

项目里的某些模块会混合使用ReactNative、Weex、H5界面,这些界面还会调用Native的界面和组件。那么,如何统一Web端和Native端请求资源的方式?

  • 如果使用了动态下发配置文件来配置App的跳转逻辑,那么如何使iOS和Android两端只用一套配置文件?

  • 如果App出现bug了,如何不用JSPatch就能实现简单的热修复功能?

例如App上线后突然遇到了紧急bug,能否将页面动态降级为H5、ReactNative、Weex?或者直接切换到一个本地的错误界面?

  • 如何在每个组件间的调用和页面跳转时都进行埋点统计?在每个跳转处都手动编写代码埋点?利用Runtime AOP?

  • 如何在每个组件间的调用过程中,加入调用逻辑检查、令牌机制,配合灰度进行风控逻辑?

  • 如何在App中的任何界面都能调用同一个界面或组件?只能在AppDelegate中注册单例来实现?

  • 例如,当App出现问题时,用户可能在任何界面,如何能随时随地进行强制登出?或者强制跳转到同一本地的error界面?或者跳转到相应的H5、ReactNative、Weex界面?如何让用户在任何界面,随时随地点击弹出View?

实际上,上述问题都可以通过在App端设计一个路由来解决。

因此,设计一个KYRouter路由来解决这些问题。

KYRouter和其它的Router有何不同?

已经有几款不错的Router,如JLRoutesHHRouter,但仔细看过之后发现,它们还是不太满足需求。

JLRoutes的问题主要在于URL查找实现不够高效,是通过遍历而不是匹配。另外功能偏多。

HHRouter的URL查找是基于匹配的,因此会更高效,KYRouter也是采用这种方法,但它与ViewController的绑定过于紧密,一定程度上降低了灵活性。

KYRouter呢?

  1. KYRouter在打开URL时,可以传递一些userinfo信息。
  2. 支持中文URL。
  3. 定义一个全局的URL模式作为后备方案。

借鉴了JLRoutes未能匹配时自动降级到全局的思想。

  1. 在打开URL完成后,可以执行Completion块。
  2. 可以统一管理URL。

如果不小心,URL的处理可能会散落在项目的各个角落,不利于管理。例如,注册时的pattern是 ky://beauty/:id,然后打开时是 KY://beauty/123,这样一旦URL发生改动,处理起来会很麻烦,不便于统一管理。

因此,KYRouter提供了一个公有类方法来解决这个问题。

#define TEMPLATE_URL @"qq://name/:name"

[KYRouter registerURLPattern:TEMPLATE_URL  toHandler:^(NSDictionary *routerParameters) {
    NSLog(@"routerParameters[name]:%@", routerParameters[@"name"]); // halfrost
}];

[KYRouter openURL:[KYRouter generateURLWithPattern:TEMPLATE_URL parameters:@[@"halfrost"]]];
}

generateURLWithPattern:函数会对我们定义的宏中的所有:进行替换,替换成后面的字符串数组,依次赋值。

安装

pod 'KYRouter', '~>1.0.0'

如何使用

最基本的使用

[KYRouter registerURLPattern:@"ky://foo/bar" toHandler:^(NSDictionary *routerParameters) {
    NSLog(@"routerParameterUserInfo:%@", routerParameters[KYRouterParameterUserInfo]);
}];

[KYRouter openURL:@"ky://foo/bar"];

当匹配到URL后,routerParameters会自带一些键

extern NSString *const KYRouterParameterURL;
extern NSString *const KYRouterParameterCompletion;
extern NSString *const KYRouterParameterUserInfo;

KYRouter支持在openURL时传输一些userinfo

[KYRouter registerURLPattern:@"ky://category/travel" toHandler:^(NSDictionary *routerParameters) {
    NSLog(@"routerParameters[KYRouterParameterUserInfo]:%@", routerParameters[KYRouterParameterUserInfo]);
    // @{@"user_id": @1900}
}];

[KYRouter openURL:@"ky://category/travel" withUserInfo:@{@"user_id": @1900} completion:nil];

支持中文URL

[KYRouter registerURLPattern:@"ky://search/直播" toHandler:^(NSDictionary *routerParameters) {
    NSLog(@"routerParameters:%@", routerParameters);
}];

[KYRouter openURL:@"ky://search/直播"];

定义一个全局的URL Pattern作为Fallback

[KYRouter registerURLPattern:@"ky://" toHandler:^(NSDictionary *routerParameters) {
    NSLog(@"没有人处理该 URL,就只能 fallback 到这里了");
}];

[KYRouter openURL:@"ky://search/travel/china?has_travelled=0"];

当OpenURL结束时,可以执行Completion Block

[KYRouter registerURLPattern:@"ky://detail" toHandler:^(NSDictionary *routerParameters) {
    NSLog(@"匹配到了 url, 一会会执行 Completion Block");

    // 模拟 push 一个 VC
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        void (^completion)() = routerParameters[KYRouterParameterCompletion];
        if (completion) {
            completion();
        }
    });
}];

[KYRouter openURL:@"ky://detail" withUserInfo:nil completion:^{
    [self appendLog:@"Open 结束,我是 Completion Block"];
}];

可以统一管理URL

URL的处理一不小心,就易散落在项目的各个角落,不易管理。例如注册时的模式为ky://beauty/:id,然后在打开时就是ky://beauty/123,这样当url有变动时,处理起来就会很麻烦,不易统一管理。

因此,KYRouter提供了一个类方法来处理这个问题。

+ (NSString *)generateURLWithPattern:(NSString *)pattern parameters:(NSArray *)parameters;

使用方式

#define TEMPLATE_URL @"ky://search/:keyword"

[KYRouter registerURLPattern:TEMPLATE_URL  toHandler:^(NSDictionary *routerParameters) {
    NSLog(@"routerParameters[keyword]:%@", routerParameters[@"keyword"]); // Hangzhou
}];

[KYRouter openURL:[KYRouter generateURLWithPattern:TEMPLATE_URL parameters:@[@"Hangzhou"]]];
}

这样就可以在一个地方定义所有的URL Pattern,使用时,用这个方法生成URL即可。

更多信息,请参考demo

协议

KYRouter许可在MIT协议下使用。查阅LICENSE文件以获取更多信息。