導(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