基于WLRRoute的移动端路由设计
本文并不是要介绍什么是移动端的路由,如果对这个概念不了解的话可以看下前人的文章,这里是 传送门。
之所以决定要在项目里面加入这个机制,是源于我们运营人员的一次偶然的需求,那就是他们希望能够通过活动页的H5链接直接打开APP,并且定位到指定的页面去,当然通过传统的方式也是可以一步一步的实现,只是需要做特殊处理罢了,具体就不多说了。
但我们想做的彻底一点,不如就此机会直接加入路由好了。没错,遇到问题当你想的比别人多一两步的时候就会看到一片新的天地。目前实现的功能已经不仅仅是运营人员所提及的那个小功能了,我们已经实现了通过短信url短连接的方式访问APP页面的功能,这个功能很早之前就有了,但是我们却一直没有加入。并且对现有的代码结构也带来了好的改变,那就是我们在进行页面跳转的时候,不需要再耦合具体的视图控制器,而是通过路由进行周转,这样的话可以大大降低代码的耦合度,当然这方面目前还没有推广开,因为大伙的编码习惯是比较难改变的。如果遇到一个强有力的领 导的话,说不定会推行这件事情。
我们的路由机制是建立在WLRRoute之上的,做这个第一步就是要搞清楚什么是页面对应的url,这里的url,并不是短连接里面所显示的那样子。比如http://m.vip.com/dcf6 这个是短信里的唯品会的链接,点击后会进入到他们的M站,而在进入M站后会提示我们是否要在软件中打开,所以这里的这个地址只是连接向唯品会M站的地址而已,通过后面所携带的dcf6参数再去他们的数据库中去查询取回所对应的APP中的路由地址。这个地址通常是 URL Schemes://url这样的格式,前面的URL Schemes是每个APP所独有的,比如我们的项目的URL Schemes是 abcmanager,而我们给首页一个地址叫做homepage的话,那这个首页所对应的地址就应该是 abcmanager://homepage, 只要在访问到M站的时候,M站返回这个地址,我们就可以打开我们的软件了。当然在这之前会弹出一个确认框,让你确认是否进入APP。比如下图。
搞清楚了这个页面所对应的路由是怎么回事就好办了,接下来我们给几乎能用的到的常用页面进行了路由的url注册,将它们写入了一个plist文件中,一种是带参数的,一种是不带参数的,如下图所示。
屏幕快照 2017-04-07 上午10.50.55.png 屏幕快照 2017-04-07 上午10.50.46.png
其中pjID是那个页面所携带的参数,为0-9之间的数字。
下面简要讲一下基于WLRRoute我们所做的二次封装。
先讲一下几个关键的类:
SpaceHomeRouter,继承于WLRRouter。功能就是注册url。
SpaceHomeRouteAnalysis,继承于NSObject,用以解析外接传入的路由信息。
SpaceHomeBaseRouteHandler,继承于WLRRouteHandler,用于快速的处理handler,而无需像demo中所展示的那样每一个都创建一个类。
最后就是RouterModel,用以承载plist文件中的数据。
具体代码如下:
SpaceHomeRouter
- (id)init{
if (self = [super init]) {
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Route" ofType:@"plist"];
//字典数组
NSArray *dicArray = [NSArray arrayWithContentsOfFile:filePath];
//字典数组转化为模型数组
_routeModelArray = [RouterModel mj_objectArrayWithKeyValuesArray:dicArray];
_allHandlers = [NSMutableArray array];
}
return self;
}
- (void)registerAllHandlers{
for (RouterModel *model in _routeModelArray) {
SpaceHomeBaseRouteHandler *routeHandler = [SpaceHomeBaseRouteHandler routeHandlerWithClsName:model.clsName ClsTab:model.clsTabPage];
[self registerHandler:routeHandler forRoute:[SHRouteBaseURL stringByAppendingString:model.clsUrl]];
[_allHandlers addObject:routeHandler];
}
}
SpaceHomeRouteAnalysis
- (void)handleURL:(NSURL *)url primitiveParameters:(NSDictionary *)primitiveParameters{
UITabBarController *tabVC = (UITabBarController *)(AppDelegate *)[UIApplication sharedApplication].delegate.window.rootViewController;
for (UINavigationController *nav in tabVC.viewControllers) {
[nav popToRootViewControllerAnimated:YES];
}
NSLog(@"SiginCallBack");
[[SpaceHomeRouter sharedSpaceHomeRouter] handleURL:url primitiveParameters:primitiveParameters targetCallBack:^(NSError *error, id responseObject) {
} withCompletionBlock:^(BOOL handled, NSError *error) {
NSLog(@"SiginHandleCompletion");
}];
}
SpaceHomeBaseRouteHandler
+ (instancetype)routeHandlerWithClsName:(NSString *)clsName ClsTab:(NSString *)clsTab{
return [[self alloc]initWithClsName:clsName clsTab:clsTab];
}
- (instancetype)initWithClsName:(NSString *)clsName clsTab:(NSString *)clsTab{
if (self = [super init]) {
_clsName = clsName;
_clsTab = clsTab;
}
return self;
}
-(UIViewController *)sourceViewControllerForTransitionWithRequest:(WLRRouteRequest *)request{
TabBarController *tabVC = (TabBarController *)[UIApplication sharedApplication].windows[0].rootViewController;
CommonNavigationViewController *nav = (CommonNavigationViewController *)tabVC.selectedViewController;
return nav;
}
-(UIViewController *)targetViewControllerWithRequest:(WLRRouteRequest *)request{
UIViewController * vc = [[NSClassFromString(_clsName) alloc]init];
return vc;
}
-(BOOL)transitionWithWithRequest:(WLRRouteRequest *)request sourceViewController:(UIViewController *)sourceViewController targetViewController:(UIViewController *)targetViewController isPreferModal:(BOOL)isPreferModal error:(NSError *__autoreleasing *)error{
if (_clsTab.intValue>0) {
TabBarController *tabVC = (TabBarController *)[UIApplication sharedApplication].windows[0].rootViewController;
tabVC.selectedIndex = _clsTab.intValue-1;
return YES;
}
if (isPreferModal||![sourceViewController isKindOfClass:[CommonNavigationViewController class]]) {
[sourceViewController presentViewController:targetViewController animated:YES completion:nil];
}
else if ([sourceViewController isKindOfClass:[CommonNavigationViewController class]]){
CommonNavigationViewController * nav = (CommonNavigationViewController *)sourceViewController;
[nav pushViewController:targetViewController animated:YES];
}
return YES;
}
最后在Appdelegate中的方法中加入下面一句代码就可以了。
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options {
[[SpaceHomeRouteAnalysis sharedSpaceHomeRouteAnalysis]handleURL:url primitiveParameters:options];
}