JLRoutes 路由跳轉(zhuǎn)使用寶典

一、簡介

JLRoutes 是一個(gè)帶有簡單的基于塊的API的URL路由庫史翘。它旨在使您在應(yīng)用程序中以最少的代碼處理復(fù)雜的URL方案變得非常簡單。

JLRoutes 可以很方便的處理不同 URL schemes 以及解析它們的參數(shù),并通過回調(diào) block 來處理 URL 對應(yīng)的操作 , 是一個(gè)可以用于處理復(fù)雜跳轉(zhuǎn)邏輯的三方庫耻蛇。

二、使用場景

  • 1胞此、在日常開發(fā)中臣咖,push、present 出現(xiàn)在整個(gè)程序的各個(gè)地方漱牵,如果你想快速理清一個(gè)項(xiàng)目的整體邏輯夺蛇,那會非常麻煩。大多數(shù)情況 , 你得找到代碼目錄酣胀,根據(jù)層級結(jié)構(gòu)分出關(guān)系刁赦,然后找到對應(yīng)的push位置,尋找下一級頁面闻镶,如果本身項(xiàng)目的目錄就非常亂甚脉,那么如果要了解一個(gè)項(xiàng)目的整體跳轉(zhuǎn)邏輯,將會更加困難铆农。
    如果能把整個(gè)項(xiàng)目的跳轉(zhuǎn)邏輯都給抽取出來牺氨,單獨(dú)放在一個(gè)類,模塊化管理,那么思路就會清晰很多猴凹,甚至可以用 XMind 根據(jù)代碼畫出整個(gè)項(xiàng)目的樹狀圖夷狰。

  • 2、如果所處公司存在多個(gè)app郊霎,app之間互相推薦互相跳轉(zhuǎn)是再正常不過的需求沼头,就類似于QQ、微信书劝、第三方分享跳轉(zhuǎn)等进倍。如果用Appdelegate 原生方法進(jìn)行攔截,所做的事至少得是判斷 Scheme 是否匹配购对,想辦法進(jìn)入需要跳到的界面背捌,如果要涉及傳參,就更加麻煩洞斯。

  • 3毡庆、如果用戶是從 PC端 識別二維碼,或者通過鏈接想要進(jìn)入 app 指定頁面烙如。

三么抗、原理

JLRoutes 本質(zhì)可以理解為:保存一個(gè)全局的字典,key 是 URL亚铁,value 是對應(yīng)存放 block 的數(shù)組蝇刀,URL 和 block 都會常駐在內(nèi)存中,當(dāng)打開一個(gè) URL 時(shí)徘溢,JLRoutes 就可以遍歷這個(gè)全局的字典吞琐,通過 URL 來執(zhí)行對應(yīng)的 block。下面是根據(jù)自己的理解畫的層次圖:

JLRoutes 層次解析圖

具體理解:

  • 1然爆、routeControllersMap 是全局的單例可變字典

  • 2站粟、這個(gè)字典的 key 值對應(yīng)一個(gè)標(biāo)識,源碼中稱之為 scheme曾雕,為了不混淆奴烙,咱們就叫其為 JLRoutes 對象標(biāo)識。這個(gè)標(biāo)識對應(yīng)的value 值為 routesController(JLRoutes類的對象:JLRoutes *routesController)剖张。

  • 3切诀、JLRoutes的對象(routesController)有很多屬性,常用的有兩個(gè)屬性:

    • NSString *scheme:也就是上面所說的 JLRoutes對象標(biāo)識搔弄,也就是說幅虑,此 value 值記錄了自己的 key 值。
    • NSMutableArray *routes:此數(shù)組中存放了JLRRouteDefinition 對象顾犹。
  • 4倒庵、JLRRouteDefinition 對象為最終的具體模型褒墨,也就是說你注冊的跳轉(zhuǎn)邏輯的所有信息,都存在于這個(gè)模型中哄芜,包括要實(shí)施操作的handlerBlock(執(zhí)行操作的block代碼塊)貌亭、scheme(JLRoutes對象標(biāo)識)柬唯、pattern(模式)认臊、priority(優(yōu)先級)。

四锄奢、開發(fā)步驟

在正式進(jìn)行 JLRoutes 開發(fā)之前失晴,了解如何通過設(shè)置app的 URL Scheme由外部跳轉(zhuǎn)到app?具體步驟我已在之前的一篇文章中詳細(xì)說明了(如何自定義 URL Scheme 進(jìn)行跳轉(zhuǎn))拘央,此處略過涂屁,不明白的可以先去大致了解下原理。

1灰伟、配置 URL Schemes

一個(gè) app 可以對應(yīng)多個(gè) URL Schemes拆又,如下圖 info.plist 配置,在 Safari 中栏账,只要輸入 JLRouteSchemeOne://JLRouteSchemeTwo:// 都可以打開該 app帖族,而 URL identifier 最好是保證其唯一性,這里咱們?yōu)閍pp設(shè)置了2個(gè) URL Schemes挡爵,是為了后面手動解析URL而做的準(zhǔn)備竖般。

配置 URL Schemes
2、注冊 JLRoutes

首先 , 考慮的問題有兩個(gè)茶鹃,一是什么時(shí)候注冊路由涣雕,二是在什么地方注冊路由。

比如一個(gè)項(xiàng)目的 tabbarItem 有2個(gè)闭翩,那么這2個(gè)模塊的跳轉(zhuǎn)挣郭,并不是由一個(gè) navigationController 來完成,所以考慮到這點(diǎn)疗韵,我們可以創(chuàng)建一個(gè)分類丈屹,將跳轉(zhuǎn)邏輯放在其中,在初始化 tabbarController 時(shí)進(jìn)行注冊路由跳轉(zhuǎn)邏輯伶棒。

注冊路由的方式有很多種:

1旺垒、全局JLRoutes注冊

[[JLRoutes globalRoutes] addRoute:@"取url內(nèi)容值的標(biāo)識" handler:^BOOL(NSDictionary<NSString *,id> * _Nonnull parameters) {
        
    return YES; // 一旦匹配,立即返回 YES
}];

此方法對應(yīng)的JLRoutes對象標(biāo)識為 JLRoutesGlobalRoutesScheme肤无,由下述源碼可知 , 用 globalRoutes 方式創(chuàng)建的JLRoutes對象先蒋,無論創(chuàng)建多少次,始終對應(yīng)著同一個(gè)實(shí)例宛渐。也就是說竞漾,無論你調(diào)用上述方法多少次眯搭,盡管 @”取url內(nèi)容值的標(biāo)識” 和 block塊內(nèi)容不一樣,最后都會執(zhí)行第一次注冊的內(nèi)容业岁。此方法和咱們要實(shí)現(xiàn)的2個(gè) tabbarItem 對應(yīng)2種跳轉(zhuǎn)要求不合鳞仙,因?yàn)樵蹅円蟮氖?block塊中的 navigationController 為2個(gè)不同的實(shí)例對象。

2笔时、自定義命名空間注冊

[[JLRoutes routesForScheme:@"第一模塊的標(biāo)識"] addRoute:@"取url內(nèi)容值的標(biāo)識" handler:^BOOL(NSDictionary<NSString *,id> * _Nonnull parameters) {
        
    return YES; // 一旦匹配棍好,立即返回 YES
}];

此注冊方法所得的JLRoutes對象都是唯一的,而這才是咱們真正需要的允耿。

3借笙、定義優(yōu)先級注冊

[[JLRoutes globalRoutes] addRoute:@"取url內(nèi)容值的標(biāo)識" priority:1 handler:^BOOL(NSDictionary<NSString *,id> * _Nonnull parameters) {
    
    return YES; // 一旦匹配,立即返回 YES
}];

簡單來說:如果不設(shè)置優(yōu)先級较锡,所有的注冊優(yōu)先級都為 0业稼。

當(dāng)標(biāo)識了優(yōu)先級進(jìn)行注冊后,JLRRouteDefinition 對象(最終模型)在 JLRoutes對象的 routes數(shù)組 中將進(jìn)行排序蚂蕴,類似于選擇排序低散,當(dāng)通過route對象尋找到其 routes數(shù)組 后,將會遍歷整個(gè) routes數(shù)組骡楼,優(yōu)先級高的 JLRRouteDefinition對象 將會被最先匹配熔号,然后return YES,并停止遍歷君编。

咱們暫時(shí)用不上這個(gè)優(yōu)先級跨嘉,就不進(jìn)行過多講述,因?yàn)樵蹅冏缘?個(gè)跳轉(zhuǎn)吃嘿,每個(gè)對應(yīng)的routes數(shù)組中元素僅為1個(gè)祠乃。

4、定義多個(gè) "取url內(nèi)容值的標(biāo)識" 進(jìn)行注冊

[[JLRoutes globalRoutes] addRoutes:@[@"取url內(nèi)容值的標(biāo)識", @"取url內(nèi)容值的標(biāo)識"] handler:^BOOL(NSDictionary<NSString *,id> * _Nonnull parameters) {
    
    return YES; // 一旦匹配兑燥,立即返回 YES
}];

我們使用第二種方法進(jìn)行注冊:取url內(nèi)容值的標(biāo)識暫時(shí)為 nil

[[JLRoutes routesForScheme:@"JLRouteSchemeOne"] addRoute:nil handler:^BOOL(NSDictionary<NSString *,id> * _Nonnull parameters) {
    
    return YES;
}];

[[JLRoutes routesForScheme:@"JLRouteSchemeTwo"] addRoute:nil handler:^BOOL(NSDictionary<NSString *,id> * _Nonnull parameters) {
    
    return YES;
}];
3亮瓷、點(diǎn)擊跳轉(zhuǎn)

在開始這兩個(gè) URL scheme 都添加進(jìn)了 info.plist,并用第二種注冊方法(自定義命名空間注冊)進(jìn)行注冊降瞳,接下來這兩個(gè)方法就可以進(jìn)行跳轉(zhuǎn):

- (void)clickBtn {
    NSString *customURL = @"JLRouteSchemeOne://OneDetailViewController";
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:customURL]];
}

- (void)clickBtn {
    NSString *customURL = @"JLRouteSchemeTwo://TwoDetailViewController";
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:customURL]];
}
4嘱支、實(shí)現(xiàn) openURL 方法

openURL方法在此處對所有的跳轉(zhuǎn)進(jìn)行攔截,手動解析處理挣饥,再交于JLRoutes除师。

手動解析URL:如果Scheme從網(wǎng)頁跳轉(zhuǎn)過來,攔截到的會變成小寫扔枫,所以直接將 URL Scheme 攔截下來汛聚,轉(zhuǎn)換小寫進(jìn)行判斷。經(jīng)過處理之后短荐,交于JLRoutes進(jìn)行解析倚舀,尋找具體的操作叹哭。

這里也解釋了為什么在 info.plist 文件中,要設(shè)定2個(gè)不同的URL Scheme痕貌。當(dāng)在2個(gè)不同模塊中進(jìn)行跳轉(zhuǎn)點(diǎn)擊時(shí)风罩,這個(gè)方法是必經(jīng)的,進(jìn)行攔截舵稠,判斷具體是哪個(gè)模塊后交于JLRoutes解析超升。

// iOS 9.0前方法
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    
    NSLog(@"Calling Application Bundle ID: %@", sourceApplication);
    NSLog(@"URL scheme: %@", [url scheme]);
    NSLog(@"URL query: %@", [url query]);
    
    // 從瀏覽器打開時(shí)候會自動全部轉(zhuǎn)成小寫,而從應(yīng)用內(nèi)調(diào)用的話大小寫不會變化
    // 為了方便判斷所以統(tǒng)一轉(zhuǎn)成小寫來判斷

    NSString *urlSchemeStr = [[url scheme] lowercaseString]; // url scheme 轉(zhuǎn)換為小寫的字符串
    NSLog(@"urlSchemeStr: %@",urlSchemeStr);
    
    if ([urlSchemeStr isEqualToString:@"jlrouteschemeone"]) {
        
        // 要和 info.plist 的 URL types 里面的一致
        return [[JLRoutes routesForScheme:@"JLRouteSchemeOne"]routeURL:url];
        
    } else if ([urlSchemeStr isEqualToString:@"jlrouteschemetwo"]) {
        
        // 要和 info.plist 的 URL types 里面的一致
        return [[JLRoutes routesForScheme:@"JLRouteSchemeTwo"]routeURL:url];
    }
    
    return YES;
    
}

// iOS 9.0后方法
- (BOOL)application:(UIApplication *)app openURL:(nonnull NSURL *)url options:(nonnull NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
    
    NSLog(@"options: %@", options);
    
    NSLog(@"Calling Application Bundle ID: %@", [options objectForKey:@"UIApplicationOpenURLOptionsSourceApplicationKey"]);
    
    NSLog(@"URL scheme: %@", [url scheme]);
    NSLog(@"URL  host : %@", [url host]);
    NSLog(@"URL  query: %@", [url query]);
    
    // 從瀏覽器打開時(shí)候會自動全部轉(zhuǎn)成小寫柱查,而從應(yīng)用內(nèi)調(diào)用的話大小寫不會變化
    // 為了方便判斷所以統(tǒng)一轉(zhuǎn)成小寫來判斷
    
    NSString *urlSchemeStr = [[url scheme] lowercaseString]; // url scheme 轉(zhuǎn)換為小寫的字符串
    NSLog(@"urlSchemeStr: %@",urlSchemeStr);
    
    if ([urlSchemeStr isEqualToString:@"jlrouteschemeone"]) {
        
        // 要和 info.plist 的 URL types 里面的一致
        return [[JLRoutes routesForScheme:@"JLRouteSchemeOne"]routeURL:url];
        
    } else if ([urlSchemeStr isEqualToString:@"jlrouteschemetwo"]) {
        
        // 要和 info.plist 的 URL types 里面的一致
        return [[JLRoutes routesForScheme:@"JLRouteSchemeTwo"]routeURL:url];
    }
    
    return YES;
}
5廓俭、參數(shù)傳遞云石,以及 tabbarController 選中問題處理

參數(shù)傳遞需要進(jìn)行一一對應(yīng)

[[JLRoutes routesForScheme:@"JLRouteSchemeTwo"]addRoute:@"/:ViewController/:userID/:pass" handler:^BOOL(NSDictionary<NSString *,id> * _Nonnull parameters) {
    
    NSLog(@"parameters: %@",parameters);
    NSLog(@"userID: %@",parameters[@"userID"]);
    NSLog(@"pass: %@",parameters[@"pass"]);
    NSLog(@"-----第二模塊-----");

    Class class = NSClassFromString(parameters[@"ViewController"]);
    [navVc pushViewController:[[class alloc]init] animated:YES];
    
    self.selectedIndex = 1; // 解決從app外跳轉(zhuǎn)進(jìn)來的 tabbar 選中問題
    
    return YES;
}];

點(diǎn)擊方法如下:

- (void)clickBtn {
    NSString *customURL = @"JLRouteSchemeTwo://TwoDetailViewController/我是userID/我是pwd";
    // 中文傳輸需要進(jìn)行轉(zhuǎn)義
    customURL = [customURL stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:customURL]];
}

處理從網(wǎng)頁等跳轉(zhuǎn)過來唉工,比如直接跳到第二模塊的第二級控制器,實(shí)際上已經(jīng)跳轉(zhuǎn)了汹忠,tabbarItem還是選中的第一個(gè)淋硝。只需要在block塊中處理一下 selectedIndex 就行。

參考鏈接:JLRoutes路由跳轉(zhuǎn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末宽菜,一起剝皮案震驚了整個(gè)濱河市谣膳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌铅乡,老刑警劉巖继谚,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異阵幸,居然都是意外死亡花履,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門挚赊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诡壁,“玉大人,你說我怎么就攤上這事荠割∶们洌” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵蔑鹦,是天一觀的道長夺克。 經(jīng)常有香客問我,道長嚎朽,這世上最難降的妖魔是什么铺纽? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮火鼻,結(jié)果婚禮上室囊,老公的妹妹穿的比我還像新娘雕崩。我一直安慰自己,他們只是感情好融撞,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布盼铁。 她就那樣靜靜地躺著,像睡著了一般尝偎。 火紅的嫁衣襯著肌膚如雪饶火。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天致扯,我揣著相機(jī)與錄音肤寝,去河邊找鬼。 笑死抖僵,一個(gè)胖子當(dāng)著我的面吹牛鲤看,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播耍群,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼义桂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蹈垢?” 一聲冷哼從身側(cè)響起慷吊,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎曹抬,沒想到半個(gè)月后溉瓶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了冗疮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片骤星。...
    茶點(diǎn)故事閱讀 40,424評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤嗅榕,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站吵聪,受9級特大地震影響凌那,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吟逝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一帽蝶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧块攒,春花似錦励稳、人聲如沸佃乘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽趣避。三九已至,卻和暖如春新翎,著一層夾襖步出監(jiān)牢的瞬間程帕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工地啰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留愁拭,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓亏吝,卻偏偏與公主長得像岭埠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子顺呕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容