Native地圖與Web融合技術(shù)的應(yīng)用與實踐

1. 背景
美團(tuán)打車業(yè)務(wù)很早就在美團(tuán)App與點評App中提供了服務(wù)入口,并在技術(shù)上采用了H5與Native的混合開發(fā)技術(shù)。隨著業(yè)務(wù)上線,有用戶反饋我們的地圖性能有一些問題,原因是我們打車地圖使用的是Web版的地圖(通過騰訊地圖JavaScript API),業(yè)內(nèi)同類產(chǎn)品使用的是Native版的地圖SDK,Native地圖相比Web地圖具有天然的性能優(yōu)勢,所以美團(tuán)打車地圖從首屏地圖加載到后續(xù)的地圖操作體驗都有一定差距。
1.1 問題與挑戰(zhàn)
為了改善打車業(yè)務(wù)的地圖體驗,我們想到的方案是在展示地圖的部分使用Native地圖,而非地圖部分使用H5頁面來顯示,這樣既能追平與競品的地圖性能差距,又能充分發(fā)揮H5的開發(fā)效率。
這種方案乍一看似乎是傳統(tǒng)的Hybrid開發(fā),沒什么難度與新奇。比如地圖使用預(yù)先內(nèi)置到App中的地圖SDK實現(xiàn),H5與Native的交互使用業(yè)界成熟的JSBridge技術(shù)。但從打車業(yè)務(wù)角度來看,因為打車業(yè)務(wù)有很多功能入口需要漂浮在地圖之上,如起終點卡片、用戶中心入口等,這種漂浮功能在技術(shù)上并不容易實現(xiàn),而且還要保證用戶觸摸動作在漂浮元素與地圖上發(fā)生時,分別派發(fā)給各自的事件系統(tǒng),Hybrid技術(shù)在這方面沒有經(jīng)驗可以借鑒。
帶著這些挑戰(zhàn),我們進(jìn)行一系列的嘗試與試驗,最終將問題解決并封裝出我們打車業(yè)務(wù)的地圖調(diào)用框架,我們稱之為Native地圖與Web融合框架(下文簡稱融合框架)。在這個過程中,我們總結(jié)出了一些經(jīng)驗,希望能給從事相關(guān)研究的同學(xué)帶來一些幫助。
1.2 融合框架上線前后的對比
其實,融合框架已經(jīng)在大眾點評App中上線了幾個月的時間了,我們可以先看看上線前后的效果對比。
優(yōu)化前,未使用融合框架時:
優(yōu)化后,使用了融合框架:
可以清晰地觀察到,使用融合框架掃碼后,地圖瞬間展示出來,相比Web地圖減少了漫長的白屏?xí)r間。
2. 調(diào)研
基于混合技術(shù)開發(fā)體系,我們研究了市面上大部分H5頁面與Native地圖的應(yīng)用場景,主要分為如下兩類:
H5頁面與Native地圖分別是2個獨立的頁面:H5業(yè)務(wù)邏輯用到地圖時候,通過交互技術(shù)打開一個新地圖頁面,在新頁面內(nèi),Native地圖按照傳入?yún)?shù)調(diào)用對應(yīng)地圖組件,完成業(yè)務(wù)功能的展示。

H5頁面與Native地圖位于同一頁面內(nèi):兩者將屏幕分割為兩部分,如下圖所示:Native地圖位于上半部分,WebView H5頁面位于下半部分。

經(jīng)過分析后,我們發(fā)現(xiàn)這兩種形式都無法滿足打車業(yè)務(wù)場景的需求,因為目前市面上主流的打車業(yè)務(wù)場景由4部分構(gòu)成,如下圖所示:
起終點選擇面板:占據(jù)頁面下半部分,可以上下滑動露出更多內(nèi)容。 地圖部分:頁面上半部分,顯示起終點、線路等地圖要素信息。 更多菜單:左上角圖標(biāo),點擊后跳轉(zhuǎn)到H5功能菜單頁面。 廣告入口:右上角圖標(biāo),點擊后跳轉(zhuǎn)到H5運營頁面。

上文第一類,H5頁面與Native地圖分別位于兩個獨立頁面中,只能滿足部分地圖場景的需求,無法布局為上圖H5與地圖同框顯示的效果。
上文第二類,實現(xiàn)這樣的布局需要多個WebView才能實現(xiàn),存在如下缺點:
下方WebView與上方Native地圖是平級的組件,各占屏幕的一半,相互間不存在壓蓋關(guān)系,實現(xiàn)起終點面板上下滑動效果困難。 左上角、右上角的更多菜單,廣告入口位置需要新增2個WebView組件才能實現(xiàn)覆蓋在地圖之上,WebView組件再加載對應(yīng)H5頁面實現(xiàn)上述布局,整個步驟比較繁瑣。 多個WebView組件構(gòu)成的頁面布局,由于內(nèi)存空間不共享,它們之間信息的同步比較困難,太多的WebView組件對系統(tǒng)性能也是一種浪費。
調(diào)研結(jié)論是:市面上現(xiàn)存技術(shù)都無法滿足打車場景的需求。
全新方案的提出
基于打車場景的特殊性,我們做了一個大膽的假設(shè):把頁面分為2層,下層是Native地圖層,布滿屏幕;上層是WebView層,完全覆蓋到Native地圖層之上,如下圖所示:

我們期望的效果是:
點擊H5元素時,點擊事件會派發(fā)給H5 WebView容器處理。 點擊地圖區(qū)域時,點擊事件會派發(fā)給Native地圖組件處理。 H5與Native地圖間的信息交互,可采用成熟的JSBridge技術(shù)實現(xiàn)。
具體實現(xiàn)思路有如下幾點,參照下圖:
Native地圖位于下層,WebView置于Native地圖之上,WebView背景透明,透過WebView可以看到下邊的地圖。紅框區(qū)域是上層WebView打開的H5頁面元素。 增加一個手勢消息分發(fā)層,該層會智能判斷手勢事件落在H5元素還是地圖元素中。舉例:點擊紅框區(qū)域,消息會傳遞到WebView層的H5邏輯處理,點擊紅框之外的區(qū)域,消息會傳遞到Native地圖層處理(地圖移動、縮放等操作)。 H5與Native地圖交互使用JSBridge完成。比如在地圖中添加一個Marker,H5層業(yè)務(wù)邏輯發(fā)出添加Marker的消息,H5層通過JSBridge技術(shù)將消息發(fā)送到Native地圖層,Native地圖收到消息后在地圖中添加Marker元素。

為了驗證想法是否正確,我們首先通過Android平臺開發(fā)出Demo,驗證這種分層智能傳遞消息的做法是可行的,該方案最大優(yōu)點是兼顧了H5的開發(fā)效率與Native地圖的高性能特性,非常符合美團(tuán)業(yè)務(wù)地圖場景的需求。為了讓想法落地時更規(guī)范、更系統(tǒng),我們進(jìn)行了如下的框架設(shè)計。
3. 框架設(shè)計
3.1 熱區(qū)數(shù)據(jù)介紹

先介紹一個“熱區(qū)數(shù)據(jù)”的概念,下圖(3.2節(jié))在手勢分發(fā)層存在著消息分發(fā)熱區(qū)數(shù)據(jù)部分,下文簡稱熱區(qū)數(shù)據(jù)。熱區(qū)數(shù)據(jù)是針對上層WebView的一個概念,只對WebView層有效,對下層Native地圖層無效。如果用戶點擊屏幕事件想讓H5來捕獲處理,可以在屏幕區(qū)域內(nèi)設(shè)置一個邏輯上的矩形區(qū)域,如:[0, 0, 50, 50](上圖左上角區(qū)域),這個數(shù)據(jù)被稱為熱區(qū)數(shù)據(jù)。
我們通過編寫代碼邏輯,控制手勢消息分發(fā)的策略,如果手勢消息發(fā)生在熱區(qū)數(shù)據(jù)矩形范圍內(nèi),我們把消息發(fā)送給WebView處理,否則發(fā)送給Native地圖處理。如上圖所示,可以在同一屏幕內(nèi)設(shè)定多個熱區(qū),[0, 0, 50, 50]、[430, 0, 50, 50]、[0, 200, 480, 200],熱區(qū)的格式可以自己定義,我們這里采用的基于WebView組件左上角為原點的像素坐標(biāo)格式:[left, top, width, height]。
3.2 框架圖介紹

手勢消息分發(fā)給WebView層流程
主要為上圖1-->2-->3-->4過程,如下:
用戶觸摸動作首先被手勢分發(fā)層捕獲,手勢分發(fā)層判斷用戶點擊到熱區(qū)數(shù)據(jù)范圍內(nèi),將消息分發(fā)到WebView H5層處理。 WebView H5層收到消息,對消息進(jìn)行處理(比如:在地圖中添加一個終點Marker),通過通訊橋?qū)⑾鬟f到Native地圖層。 Native地圖層收到消息,并執(zhí)行添加Marker操作,完成后返回成功信息。上述總體流程為:手勢分發(fā)層-->1-->2-->3-->6-->7。
手勢消息分發(fā)給Native地圖層流程
主要為上圖5-->6-->7過程,如下:
手勢分發(fā)層捕獲到消息,發(fā)現(xiàn)用戶手勢與當(dāng)前熱區(qū)數(shù)據(jù)矩形沒有交集,于是將獲取的消息分發(fā)到Native地圖層。 如果消息是拖動操作,則Native地圖自動識別拖動地圖消息,實現(xiàn)移動地圖的效果,涉及流程為:手勢分發(fā)層-->5。 如果消息是點擊操作,比如我們想實現(xiàn)點擊地圖中的Marker,將消息傳遞給H5處理的功能。實現(xiàn)步驟為我們事先在添加Marker時增加一個點擊事件(Native地圖層實現(xiàn)),Marker被點擊時Native地圖層會派發(fā)此事件,事件消息會通過JSBridge技術(shù)從Native地圖層傳到H5層,最后H5層獲取到點擊消息。整個操作流程為:手勢分發(fā)層-->5-->6-->7。
熱區(qū)數(shù)據(jù)的動態(tài)更新策略
因為打車業(yè)務(wù)底部的面板高度是可伸縮的,所以底部的熱區(qū)數(shù)據(jù)并不是靜止不動的,需要考慮熱區(qū)數(shù)據(jù)也要隨著DOM元素的拉伸做同步調(diào)整??梢酝ㄟ^在WebView H5層監(jiān)控DOM的變化,DOM元素發(fā)生變化時,獲取變化后的DOM元素位置、大小,格式化為熱區(qū)數(shù)據(jù),并更新到消息分發(fā)熱區(qū)數(shù)據(jù)部分。因為拉伸動作是一個連續(xù)的動畫效果,為了高效,我們只在動畫結(jié)束的那一刻更新熱區(qū)數(shù)據(jù),中間過渡期不做處理。此整體流程為:2-->3-->4。
4. 點評App中的落地實踐
4.1 手勢分發(fā)層關(guān)鍵代碼
這部分功能需要Native端同學(xué)實現(xiàn),包括iOS與Android。兩端分別在啟動App時設(shè)置三層內(nèi)容,最上層是手勢觸摸事件接收層,中間是WebView層(背景設(shè)置透明),最下層是Native地圖層(如騰訊地圖SDK)。用數(shù)組記錄當(dāng)前熱區(qū)數(shù)據(jù),當(dāng)手勢分發(fā)層有事件發(fā)生時,通過Touch事件獲取手指位置信息,遍歷熱區(qū)數(shù)組判斷手指位置是否與熱區(qū)的矩形相交,如相交則將消息分發(fā)給WebView層,否則分發(fā)給Native層。下邊是Android與iOS消息分發(fā)關(guān)鍵代碼:
@Override
public boolean dispatchTouchEvent(MotionEvent event){
if(event.getAction() == MotionEvent.ACTION_DOWN) {
// 分發(fā)層接收到手勢觸摸消息,通過dispatchService類判斷手勢是否落在熱區(qū)內(nèi),從而確定消息分發(fā)的對象
this.touchHandler = dispatchService.inRegion(event) ? TouchHandler.WebView : TouchHandler.MapView;
}
// 分發(fā)給Native地圖層
if(this.touchHandler == TouchHandler.MapView) {
return this.mapView.dispatchTouchEvent(event);
}
// 分發(fā)給WebView H5層
return super.dispatchTouchEvent(event);
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *hitTestView = nil;
// 分發(fā)層接收到手勢觸摸消息,通過pointInHotspot判斷手勢是否落在熱區(qū)內(nèi),從而確定消息分發(fā)的對象
if ([self pointInHotspot:point]) {
// 分發(fā)給WebView H5層
hitTestView = [self.WebView hitTest:point withEvent:event];
}else{
// 分發(fā)給Native地圖層
hitTestView = [self.mapView hitTest:point withEvent:event];
}
return hitTestView;
}
4.2 WebView H5層
該層有2個功能:
提供設(shè)置熱區(qū)的JS接口setHotRegion,業(yè)務(wù)可通過此接口設(shè)置屏幕中的熱區(qū)。 封裝一層JS形式的地圖接口,為上層業(yè)務(wù)提供地圖服務(wù),該層借助JSBridge通訊橋?qū)崿F(xiàn)H5與Native層的異步通訊。

4.3 通訊橋簡介
通訊橋即JSBridge技術(shù),主要實現(xiàn)H5與Native的信息交互,這方面的技術(shù)都已比較成熟,業(yè)界有非常多的JSBridge實現(xiàn),原理也都類似,常見的有:原生對象注入到H5層、URL攔截技術(shù),Native調(diào)用JS常用的內(nèi)置函數(shù)stringByEvaluatingJavaScriptFromString等。美團(tuán)內(nèi)部有比較成熟的KNB框架,所以項目中直接使用了KNB框架。
4.4 Native地圖層

4.5 Dom元素?zé)釁^(qū)數(shù)據(jù)的自動維護(hù)技術(shù)
打車業(yè)務(wù)前端的技術(shù)棧是: Vue + VueX + Vue-Router構(gòu)建的單頁系統(tǒng)。如下圖所示,頁面中存在很多H5元素需要添加熱區(qū),逐個元素編寫代碼添加的話會很繁瑣,而且頁面元素的位置、大小變化時還需要同步更新熱區(qū)數(shù)據(jù),這里我們使用了Vue中的directive(指令)來解決了此問題。

以上左右2圖是用戶操作時頁面展示的不同狀態(tài),很明顯右圖底部卡片變高了,卡片變化同時需要同步更新對應(yīng)的熱區(qū)數(shù)據(jù),directive技術(shù)可以很方便解決此問題,原理如下:
在添加元素時,Vue指令的bind鉤子函數(shù)被觸發(fā),此時計算出彈窗元素的大小和位置:使用getBoundingClientRect函數(shù)可以獲取到元素的left、top、width、height等信息,將新的熱區(qū)數(shù)據(jù)通過setHotRegion函數(shù)更新到手勢分發(fā)層。 在移除元素時,unbind鉤子函數(shù)被觸發(fā),此時將熱區(qū)數(shù)據(jù)移除,這樣便實現(xiàn)了熱區(qū)的自動添加刪除功能了。 使用指令技術(shù)很簡捷,編寫好指令的邏輯后注冊到全局,在需要動態(tài)更新熱區(qū)的元素上設(shè)置個v-hotRegion標(biāo)簽就可以了。
4.6 調(diào)試工具及測試
調(diào)試工具使用模擬器、真機(jī)都可以,開發(fā)期間我們使用的模擬器開發(fā),測試期間QA使用真機(jī)驗證。調(diào)試過程中主要驗證2部分功能,分別是熱區(qū)的驗證與地圖接口驗證。
熱區(qū)驗證
主要驗證主頁面設(shè)置的熱區(qū)是否正確,包括是否可以點擊、底部卡片是否能正常拖拉、業(yè)務(wù)功能是否正常等。因為熱區(qū)數(shù)據(jù)是一串?dāng)?shù)字,形如:[0, 0, 50, 50],無法直觀判斷出該數(shù)據(jù)是否有誤,于是我們開發(fā)了一個可視化工具,將設(shè)置熱區(qū)的元素都用紅色矩形高亮顯示,如下圖所示,這樣就能快速診斷出熱區(qū)數(shù)據(jù)是否有異常。工具是使用Canvas畫布實現(xiàn)的,畫布大小與屏幕大小完全重合,借助畫布就可以將矩形熱區(qū)數(shù)據(jù)在屏幕中實時繪制出來。

地圖接口驗證
主要是編寫單元測試完成的,本項目封裝了50多個地圖接口,每個接口都編寫單測用例,觀察入?yún)?、出參、控制臺輸出結(jié)果,地圖展示效果是否正確等。測試主要在iOS模擬器中完成,這樣方便在控制臺打印一些調(diào)試信息進(jìn)行診斷。
5. 上線效果
地圖的操作體驗,如地圖移動、縮放明顯好于H5地圖,用戶利用Native地圖選擇起終點、下單叫車、接送駕小車動畫效果更加流暢。 首屏地圖數(shù)據(jù)指標(biāo)也有顯著提升,如下表所示:

目前線上運行穩(wěn)定,上線2月期間,Crash數(shù)量為個位數(shù),Crash率遠(yuǎn)低于0.1‰。 框架上線后,大眾點評App中業(yè)務(wù)迭代可以按照H5節(jié)奏上線,實現(xiàn)隨時發(fā)版的開發(fā)效率。
Native地圖層代碼接口穩(wěn)定、功能豐富,基本滿足地圖場景的業(yè)務(wù)需求。只需首次跟版發(fā)布,后續(xù)只需要迭代H5的業(yè)務(wù)邏輯即可。
6. 本文小結(jié)
本文將WebView與Native地圖組件疊加到一起,實現(xiàn)了用戶手勢事件智能分發(fā)的機(jī)制,解決了WebView與Native地圖在同一頁面內(nèi)布局困難的問題。這種融合機(jī)制為打車業(yè)務(wù)提升迭代效率同時保障地圖體驗提供了一種有效的途徑,日常業(yè)務(wù)功能上線采用H5技術(shù)迭代,Native地圖作為不常更新的基礎(chǔ)能力首次發(fā)版時安裝到用戶手機(jī)上,實現(xiàn)業(yè)務(wù)需求隨時發(fā)版的能力,不再受各大應(yīng)用商店的限制,用戶操作地圖的體驗也更加流暢。該融合框架適合以下業(yè)務(wù)場景:
業(yè)務(wù)中使用了地圖功能,并對地圖的加載、操作體驗等有較高要求的業(yè)務(wù)。
業(yè)務(wù)屬于Hybrid業(yè)務(wù),并且H5頁面與地圖在同一頁面內(nèi)布局的功能。
如果你的業(yè)務(wù)是基于多個WebView與Native地圖構(gòu)建的系統(tǒng),非常建議你了解下此文章。
7. 作者簡介
美團(tuán)打車技術(shù)部終端研發(fā)中心,加鵬、張斌、楊睿、邱博、海峰等。
招聘信息
