滴滴開(kāi)源DRouter:一款高效的Android路由框架

導(dǎo)讀

DRouter是滴滴乘客端自研的一套Android路由框架纲仍,基于平臺(tái)化解耦的思想,為組件間通信服務(wù)初厚。該項(xiàng)目以功能全面件蚕、易用為原則,支持各種路由場(chǎng)景产禾,在頁(yè)面路由排作、服務(wù)獲取和過(guò)濾、跨進(jìn)程及跨應(yīng)用亚情、VirtualApk插件支持等方面都能提供多樣化的服務(wù)妄痪。目前已在滴滴乘客端、順風(fēng)車楞件、單車衫生、國(guó)際化、滴滴定制車中控、滴滴車載屏等十多個(gè)滴滴的app內(nèi)使用,得到各種場(chǎng)景的驗(yàn)證普办。

1.

DRouter簡(jiǎn)介

隨著業(yè)務(wù)不斷的發(fā)展,業(yè)務(wù)變的種類繁多泪酱,項(xiàng)目代碼集中且耦合在一起,導(dǎo)致編譯速度慢毅舆、開(kāi)發(fā)效率低西篓、維護(hù)困難、牽一發(fā)動(dòng)全身憋活。這時(shí)無(wú)論是從工程效能還是業(yè)務(wù)迭代穩(wěn)定性的角度考慮岂津,都需要把項(xiàng)目代碼拆分成獨(dú)立的組件。當(dāng)組件拆分后悦即,在沒(méi)有代碼耦合的前提下吮成,如何快速橱乱、方便、靈活的進(jìn)行組件間跳轉(zhuǎn)粱甫、數(shù)據(jù)通信泳叠、生命周期控制是DRouter要解決的問(wèn)題。

支持的功能

使用URI字符串導(dǎo)航Activity茶宵、Fragment危纫、View、RouterHandler

路由注解支持正則表達(dá)式乌庶、占位符

回調(diào)式onActivityResult

RouterHandler种蝶、Activity支持等待異步完成(hold),并可設(shè)置超時(shí)時(shí)間

RouterHandler指定執(zhí)行線程

注入攔截器瞒大,支持全局?jǐn)r截器和局部攔截器螃征,面向切面編程

更為多樣化的Fragment頁(yè)面跳轉(zhuǎn)能力

使用接口或基類導(dǎo)航到實(shí)現(xiàn)類Service的Class以及實(shí)例

支持Service別名以及多維過(guò)濾器查找

導(dǎo)航Service可指定任意構(gòu)造器、支持單例

支持動(dòng)態(tài)注冊(cè)RouterHandler透敌、Service盯滚,綁定生命周期自動(dòng)解綁

簡(jiǎn)單易用的跨進(jìn)程執(zhí)行RouterHandler、Service

跨進(jìn)程訪問(wèn)無(wú)需提前綁定酗电、如同本地調(diào)用一樣進(jìn)行訪問(wèn)

支持客戶端進(jìn)程和服務(wù)端進(jìn)程自動(dòng)重連

支持VirtualApk

2.

為什么要開(kāi)發(fā)DRouter

滴滴乘客端包容萬(wàn)象魄藕,擁有眾多的業(yè)務(wù)和組件,早在15年就已經(jīng)啟動(dòng)組件化重構(gòu)撵术。使用滴滴自研的基于JavaSPI插件技術(shù)泼疑,動(dòng)態(tài)的生成從接口到實(shí)現(xiàn)的映射關(guān)系,完成了組件化的通信功能荷荤,并且應(yīng)用到了整個(gè)滴滴的Android體系中。雖然SPI性能優(yōu)良移稳、使用便捷蕴纳,但同時(shí)功能單一、支持的場(chǎng)景少也是一直存在的問(wèn)題个粱。隨著組件化實(shí)踐的常態(tài)化古毛,急需要一款功能強(qiáng)大,適合滴滴的場(chǎng)景都许,定制化程度高的路由框架稻薇。

目前市面上已經(jīng)存在幾款路由框架了,比如ARouter胶征,WMRouter塞椎。不過(guò)滴滴業(yè)務(wù)繁多,平臺(tái)化遍布各種場(chǎng)景睛低,對(duì)路由的定制化需求強(qiáng)烈案狠,很多功能市面上的路由是不支持的服傍,比如:

ARouter作為路由的先行者,由于開(kāi)發(fā)較早功能簡(jiǎn)單骂铁,路由查找過(guò)程性能損耗較大

WMRouter在路由的性能上仍然有一定優(yōu)化空間吹零,沒(méi)有導(dǎo)航到Fragment/View、回調(diào)式ActivityResult拉庵,使用ServiceLoader稍顯繁瑣且無(wú)法動(dòng)態(tài)注冊(cè)以及多維過(guò)濾

現(xiàn)今沒(méi)有一款路由框架對(duì)完整的跨進(jìn)程和跨應(yīng)用有較好的支持灿椅,這在滴滴定制車團(tuán)隊(duì)有著強(qiáng)訴求

同時(shí)沒(méi)有一款路由對(duì)Fragment提供更多的擴(kuò)展能力,DRouter在鴻鵠和車載屏項(xiàng)目以及更多Fragment的場(chǎng)景可以提供支持

基于以上問(wèn)題钞支,從18年開(kāi)始自研了DRouer路由框架茫蛹,為滴滴的平臺(tái)化服務(wù)幾十種場(chǎng)景。

3.

DRouter有哪些亮點(diǎn)

1. 插件增量編譯伸辟、多線程掃描麻惶,運(yùn)行時(shí)異步加載路由表

路由表在編譯期通過(guò)插件動(dòng)態(tài)生成。插件會(huì)啟動(dòng)多線程同時(shí)異步處理所有的組件信夫;增量掃描功能可以幫助開(kāi)發(fā)者在第二次編譯時(shí)窃蹋,只對(duì)修改過(guò)的代碼進(jìn)行處理,極大地縮短路由表生成的時(shí)間静稻。

在本人的開(kāi)發(fā)機(jī)上測(cè)試警没,19年滴滴乘客端掃描5.5萬(wàn)個(gè)類,全量需要不到6s的時(shí)間振湾;如果是修改了application模塊杀迹,增量掃描只需要處理修改的單類,耗時(shí)0.4s時(shí)間押搪;如果是修改了library組件树酪,增量掃描需要掃描整個(gè)jar包,根據(jù)jar包的大小時(shí)間會(huì)稍多一些大州,例如滴滴屝铮快組件增量耗時(shí)3.9s。

另外框架初始化的時(shí)候啟動(dòng)子線程去加載路由表厦画,不阻塞主線程的執(zhí)行疮茄,盡其所能提高效率。

2. 完整的Router功能

支持使用URI字符串導(dǎo)航Activity根暑、Fragment力试、View、RouterHandler排嫌,支持優(yōu)先級(jí)畸裳、正則表達(dá)式、占位符躏率、回調(diào)式onActivityResult躯畴、攔截器民鼓;RouterHandler還支持異步完成(不阻塞)、指定執(zhí)行線程等等蓬抄;同時(shí)針對(duì)Fragment丰嘉,支持單Page、棧Page嚷缭、ViewPager三種形式的Fragment加載饮亏。

3. 強(qiáng)大的ServiceLoader能力

DRouter同樣是基于SPI的理念,路由表會(huì)生成接口或基類對(duì)實(shí)現(xiàn)類的映射阅爽。

獲取實(shí)例時(shí)可以指定執(zhí)行任意構(gòu)造器路幸、單例、優(yōu)先級(jí)排序付翁、自動(dòng)拆解所有接口和基類作為key

可以通過(guò)alias简肴,以及任意數(shù)量多的維度對(duì)目標(biāo)進(jìn)行過(guò)濾

動(dòng)態(tài)注冊(cè)

4. 像調(diào)用本地方法一樣進(jìn)行跨進(jìn)程通信和回調(diào)

無(wú)需編寫繁瑣的aidl文件實(shí)現(xiàn)跨進(jìn)程調(diào)用,使用方式幾乎等同本地導(dǎo)航RouterHandler和Service百侧,只需增加一些配置即可砰识。

不需要異步去bindService等待,同步執(zhí)行

支持跨應(yīng)用

替代反射佣渴,服務(wù)端使用本地方法執(zhí)行辫狼,提高執(zhí)行效率

支持任意類型的對(duì)象跨進(jìn)程傳遞,包括Context辛润、自定義類膨处,支持RemoteCallback回調(diào)

服務(wù)端異常崩潰重啟后,客戶端按需自動(dòng)重新執(zhí)行已發(fā)送的跨進(jìn)程命令

5. 框架內(nèi)部盡可能減少使用反射砂竖,提升性能

加載路由表真椿、實(shí)例化路由、以及跨進(jìn)程命令到達(dá)服務(wù)端后的分發(fā)這些常規(guī)應(yīng)該使用反射的場(chǎng)景乎澄,使用預(yù)占位或動(dòng)態(tài)生成代碼來(lái)替換成java的new創(chuàng)建和顯式方式執(zhí)行瀑粥,最大限度的去避免反射執(zhí)行,提高性能三圆。

考慮到功能的全面性,使用ServiceLoader時(shí)如指定非默認(rèn)構(gòu)造函數(shù)以及跨進(jìn)程時(shí)傳遞自定義類避咆,在框架內(nèi)部會(huì)使用到反射舟肉,不過(guò)可以使用默認(rèn)構(gòu)造函數(shù)以及對(duì)跨進(jìn)程對(duì)象實(shí)現(xiàn)Parcelable來(lái)避免。

6. 動(dòng)態(tài)下載與api匹配的plugin查库,插件自升級(jí)

很多項(xiàng)目包括DRouter需要搭配gradle插件和java依賴來(lái)使用路媚,正常來(lái)講升級(jí)java依賴時(shí)大概率需要同時(shí)升級(jí)gradle插件,這在滴滴這種業(yè)務(wù)線繁多樊销,各業(yè)務(wù)線除了有自己的組件同時(shí)又有自己的殼工程場(chǎng)景是一個(gè)非常痛的點(diǎn)整慎。當(dāng)業(yè)務(wù)線的組件因平臺(tái)的同學(xué)在公共層升級(jí)了java依賴后脏款,但又沒(méi)有同時(shí)手動(dòng)更新自己業(yè)務(wù)殼工程的gradle插件,大概率就會(huì)編譯失敗裤园。

DRouter利用plugin-proxy殼插件來(lái)解決這個(gè)問(wèn)題撤师,殼插件會(huì)在編譯期自動(dòng)檢查java依賴的版本,同時(shí)獲得應(yīng)該匹配的插件版本拧揽。接著plugin-proxy會(huì)去下載這個(gè)匹配的gradle插件剃盾,并最終執(zhí)行。這樣就解決了因升級(jí)java依賴而gradle插件不匹配導(dǎo)致的編譯問(wèn)題淤袜。

7. 無(wú)需手動(dòng)添加混淆規(guī)則

DRouter把混淆規(guī)則隱藏到了java依賴?yán)镅髑矗?dāng)啟用混淆功能時(shí)會(huì)自動(dòng)應(yīng)用混淆規(guī)則。這樣即使升級(jí)了DRouter版本也無(wú)需關(guān)心混淆規(guī)則是否需要升級(jí)铡羡。

4.

DRouter的原理和架構(gòu)

架構(gòu)設(shè)計(jì)

整體架構(gòu)分三層积蔚,自下而上是數(shù)據(jù)流層、組件層烦周、開(kāi)放接口層尽爆。

1. 數(shù)據(jù)流層

數(shù)據(jù)流層是DRouter最重要的核心模塊,這里承載著插件生成的路由表论矾、路由元素教翩、動(dòng)態(tài)注冊(cè)、以及跨進(jìn)程功能相關(guān)的序列化數(shù)據(jù)流贪壳。所有的路由流轉(zhuǎn)都會(huì)從這里取得對(duì)應(yīng)的數(shù)據(jù)饱亿,進(jìn)而流向正確的目標(biāo)。

2. 組件層

這一層是功能組件層闰靴,核心的路由分發(fā)彪笼、攔截器、生命周期蚂且、異步暫存和監(jiān)控配猫、ServiceLoader、多維過(guò)濾杏死、Fragment路由泵肄,以及跨進(jìn)程命令打包等。

3. 開(kāi)放接口層

DRouter在接口層做了大量的精簡(jiǎn)和優(yōu)化淑翼,在靈活性和易用性方面做了很多權(quán)衡腐巢,主要目的是減少冗余API,使框架更為簡(jiǎn)單的使用和接入玄括。比如Request和ServiceLoader作為最核心的API方法數(shù)非常少冯丙,一些不常用的功能會(huì)放到Extend中。

功能原理

1. RouterFlow

路由數(shù)據(jù)流從創(chuàng)建Request開(kāi)始遭京,通過(guò)URI在路由表中找出所有的結(jié)點(diǎn)胃惜,會(huì)按照RouterHandler泞莉、UI的順序以及優(yōu)先級(jí)順序執(zhí)行。每一個(gè)元素都可以定義自己的攔截器船殉,這里的攔截器必須放行以后才能執(zhí)行對(duì)應(yīng)的結(jié)點(diǎn)鲫趁;同時(shí)對(duì)于RouterHandler執(zhí)行完又可以決定是否攔截后面所有的結(jié)點(diǎn)。當(dāng)所有的結(jié)點(diǎn)執(zhí)行完捺弦,且異步暫存態(tài)也都已釋放饮寞,最終把結(jié)果回傳給請(qǐng)求處。

2. ServiceFlow

ServiceLoader既可以獲取Class也可以獲取對(duì)象實(shí)例列吼,核心是路由表和過(guò)濾器幽崩,其中FeatureMatcher擁有多維過(guò)濾的功能。像滴滴這種多業(yè)務(wù)場(chǎng)景的應(yīng)用寞钥,在使用MVP架構(gòu)時(shí)對(duì)P的匹配至少會(huì)需要根據(jù)所在國(guó)家慌申、訂單業(yè)務(wù)線、訂單狀態(tài)三個(gè)維度來(lái)分別對(duì)應(yīng)唯一的Presenter理郑,多維過(guò)濾就很容易解決這個(gè)問(wèn)題蹄溉。性能方面,對(duì)象實(shí)例化會(huì)根據(jù)構(gòu)造器類型您炉,利用插件生成的RouterProxy代碼通過(guò)new來(lái)實(shí)例化無(wú)參對(duì)象(默認(rèn)構(gòu)造)或者反射實(shí)例化有參對(duì)象(非默認(rèn)構(gòu)造)柒爵。

3. RemoteFlow

DRouter的跨進(jìn)程功能是一大特色,左側(cè)綠色代表客戶端赚爵,自上而下會(huì)把所有的參數(shù)打包成命令棉胀,這里支持任意類型,框架內(nèi)有一套完整的機(jī)制通過(guò)遍歷集合冀膝、轉(zhuǎn)換唁奢、組裝,最后存儲(chǔ)到Parcel里窝剖。利用Authority查找到服務(wù)端的Provider并隨之利用此通道返回服務(wù)端的Binder麻掸。

在服務(wù)端,也就是右側(cè)的紫色赐纱,會(huì)自下而上把命令解包和分發(fā)脊奋。然后利用DRouter的路由RouterHandler和ServiceLoader的功能,使得客戶端的命令最終在服務(wù)端執(zhí)行疙描。插件會(huì)在服務(wù)端生成一段代碼狂魔,這段代碼可以避免使用反射,提高整體的執(zhí)行效率淫痰。

整個(gè)過(guò)程同步執(zhí)行,使用簡(jiǎn)單整份、高效待错。

5.

寫在最后

DRouter是一套功能完善籽孙、定制化程度高的路由框架,具有易于上手火俄、架構(gòu)清晰犯建、性能優(yōu)良的特點(diǎn)。現(xiàn)已成為滴滴不可或缺的基礎(chǔ)組件之一瓜客。

從統(tǒng)計(jì)數(shù)據(jù)看适瓦,公司內(nèi)外目前已有62個(gè)不同的app接入DRouter,在此感謝各位的信任和支持谱仪。DRouter作為組件化方案的踐行者玻熙,將繼續(xù)提升各個(gè)場(chǎng)景的支持能力,并會(huì)一直進(jìn)行問(wèn)題修復(fù)以及功能更新疯攒,也歡迎各位開(kāi)發(fā)者使用并提出寶貴的反饋意見(jiàn)嗦随。


6.

使用文檔

GitHub開(kāi)源地址 https://github.com/didi/DRouter

接入和使用文檔? ? https://github.com/didi/DRouter/wiki

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市敬尺,隨后出現(xiàn)的幾起案子枚尼,更是在濱河造成了極大的恐慌,老刑警劉巖砂吞,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件署恍,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蜻直,警方通過(guò)查閱死者的電腦和手機(jī)盯质,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)袭蝗,“玉大人唤殴,你說(shuō)我怎么就攤上這事〉叫龋” “怎么了朵逝?”我有些...
    開(kāi)封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)乡范。 經(jīng)常有香客問(wèn)我配名,道長(zhǎng),這世上最難降的妖魔是什么晋辆? 我笑而不...
    開(kāi)封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任渠脉,我火速辦了婚禮,結(jié)果婚禮上瓶佳,老公的妹妹穿的比我還像新娘芋膘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布为朋。 她就那樣靜靜地躺著臂拓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪习寸。 梳的紋絲不亂的頭發(fā)上胶惰,一...
    開(kāi)封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音霞溪,去河邊找鬼孵滞。 笑死,一個(gè)胖子當(dāng)著我的面吹牛鸯匹,可吹牛的內(nèi)容都是我干的坊饶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼忽你,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼幼东!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起科雳,我...
    開(kāi)封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤根蟹,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后糟秘,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體简逮,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年尿赚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了散庶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡凌净,死狀恐怖悲龟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情冰寻,我是刑警寧澤须教,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站斩芭,受9級(jí)特大地震影響轻腺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜划乖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一贬养、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧琴庵,春花似錦误算、人聲如沸仰美。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)筒占。三九已至,卻和暖如春蜘犁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背止邮。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工这橙, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人导披。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓屈扎,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親撩匕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鹰晨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

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