Native地圖與Web融合技術的應用與實踐

1. 背景

美團打車業務很早就在美團App與點評App中提供了服務入口,並在技術上採用了H5與Native的混合開發技術。隨着業務上線,有用戶反饋咱們的地圖性能有一些問題,緣由是咱們打車地圖使用的是Web版的地圖(經過騰訊地圖JavaScript API),業內同類產品使用的是Native版的地圖SDK,Native地圖相比Web地圖具備自然的性能優點,因此美團打車地圖從首屏地圖加載到後續的地圖操做體驗都有必定差距​。前端

問題和挑戰

爲了改善打車業務的地圖體驗,咱們想到的方案是在展現地圖的部分使用Native地圖,而非地圖部分使用H5頁面來顯示,這樣既能追平與競品的地圖性能差距,又能充分發揮H5的開發效率。這種方案乍一看彷佛是傳統的Hybrid開發,沒什麼難度與新奇。好比地圖使用預先內置到App中的地圖SDK實現,H5與Native的交互使用業界成熟的JSBridge技術。但從打車業務角度來看,由於打車業務有不少功能入口須要漂浮在地圖之上,如起終點卡片、用戶中心入口等,這種漂浮功能在技術上並不容易實現,並且還要保證用戶觸摸動做在漂浮元素與地圖上發生時,分別派發給各自的事件系統,Hybrid技術在這方面沒有經驗能夠借鑑。數組

帶着這些挑戰,咱們進行一系列的嘗試與試驗,最終將問題解決並封裝出咱們打車業務的地圖調用框架,咱們稱之爲Native地圖與Web融合框架(下文簡稱融合框架)。在這個過程當中,咱們總結出了一些經驗,但願能給從事相關研究的同窗帶來一些幫助。微信

2. 調研

基於混合技術開發體系,咱們研究了市面上大部分H5頁面與Native地圖的應用場景,主要分爲以下兩類:框架

  • H5頁面與Native地圖分別是2個獨立的頁面:H5業務邏輯用到地圖時候,經過交互技術打開一個新地圖頁面,在新頁面內,Native地圖按照傳入參數調用對應地圖組件,完成業務功能的展現。

  • H5頁面與Native地圖位於同一頁面內:二者將屏幕分割爲兩部分,以下圖所示:Native地圖位於上半部分,WebView H5頁面位於下半部分。

通過分析後,咱們發現這兩種形式都沒法知足打車業務場景的需求,由於目前市面上主流的打車業務場景由4部分構成,以下圖所示:異步

  • 起終點選擇面板:佔據頁面下半部分,能夠上下滑動露出更多內容。
  • 地圖部分:頁面上半部分,顯示起終點、線路等地圖要素信息。
  • 更多菜單:左上角圖標,點擊後跳轉到H5功能菜單頁面。
  • 廣告入口:右上角圖標,點擊後跳轉到H5運營頁面。

上文第一類,H5頁面與Native地圖分別位於兩個獨立頁面中,只能知足部分地圖場景的需求,沒法佈局爲上圖H5與地圖同框顯示的效果。ide

上文第二類,實現這樣的佈局須要多個WebView才能實現,存在以下缺點:函數

  • 下方WebView與上方Native地圖是平級的組件,各佔屏幕的一半,相互間不存在壓蓋關係,實現起終點面板上下滑動效果困難。
  • 左上角、右上角的更多菜單,廣告入口位置須要新增2個WebView組件才能實現覆蓋在地圖之上,WebView組件再加載對應H5頁面實現上述佈局,整個步驟比較繁瑣。
  • 多個WebView組件構成的頁面佈局,因爲內存空間不共享,它們之間信息的同步比較困難,太多的WebView組件對系統性能也是一種浪費。

調研結論是:市面上現存技術都沒法知足打車場景的需求。工具

全新方案的提出

基於打車場景的特殊性,咱們作了一個大膽的假設:把頁面分爲2層,下層是Native地圖層,佈滿屏幕;上層是WebView層,徹底覆蓋到Native地圖層之上,以下圖所示:佈局

咱們指望的效果是:性能

  • 點擊H5元素時,點擊事件會派發給H5 WebView容器處理。
  • 點擊地圖區域時,點擊事件會派發給Native地圖組件處理。
  • H5與Native地圖間的信息交互,可採用成熟的JSBridge技術實現。

具體實現思路有以下幾點,參照下圖:

  • Native地圖位於下層,WebView置於Native地圖之上,WebView背景透明,透過WebView能夠看到下邊的地圖。紅框區域是上層WebView打開的H5頁面元素。
  • 增長一個手勢消息分發層,該層會智能判斷手勢事件落在H5元素仍是地圖元素中。舉例:點擊紅框區域,消息會傳遞到WebView層的H5邏輯處理,點擊紅框以外的區域,消息會傳遞到Native地圖層處理(地圖移動、縮放等操做)。
  • H5與Native地圖交互使用JSBridge完成。好比在地圖中添加一個Marker,H5層業務邏輯發出添加Marker的消息,H5層經過JSBridge技術將消息發送到Native地圖層,Native地圖收到消息後在地圖中添加Marker元素。

爲了驗證想法是否正確,咱們首先經過Android平臺開發出Demo,驗證這種分層智能傳遞消息的作法是可行的,該方案最大優勢是兼顧了H5的開發效率與Native地圖的高性能特性,很是符合美團業務地圖場景的需求。爲了讓想法落地時更規範、更系統,咱們進行了以下的框架設計。

3. 框架設計

3.1 熱區數據介紹

先介紹一個「熱區數據」的概念,下圖(3.2節)在手勢分發層存在着消息分發熱區數據部分,下文簡稱熱區數據。熱區數據是針對上層WebView的一個概念,只對WebView層有效,對下層Native地圖層無效。若是用戶點擊屏幕事件想讓H5來捕獲處理,能夠在屏幕區域內設置一個邏輯上的矩形區域,如:[0, 0, 50, 50](上圖左上角區域),這個數據被稱爲熱區數據

咱們經過編寫代碼邏輯,控制手勢消息分發的策略,若是手勢消息發生在熱區數據矩形範圍內,咱們把消息發送給WebView處理,不然發送給Native地圖處理。如上圖所示,能夠在同一屏幕內設定多個熱區,[0, 0, 50, 50]、[430, 0, 50, 50]、[0, 200, 480, 200],熱區的格式能夠本身定義,咱們這裏採用的基於WebView組件左上角爲原點的像素座標格式:[left, top, width, height]。

3.2 框架圖介紹

手勢消息分發給WebView層流程

主要爲上圖1-->2-->3-->4過程,以下:

  • 用戶觸摸動做首先被手勢分發層捕獲,手勢分發層判斷用戶點擊到熱區數據範圍內,將消息分發到WebView H5層處理。
  • WebView H5層收到消息,對消息進行處理(好比:在地圖中添加一個終點Marker),經過通信橋將消息傳遞到Native地圖層。
  • Native地圖層收到消息,並執行添加Marker操做,完成後返回成功信息。上述整體流程爲:手勢分發層-->1-->2-->3-->6-->7。

手勢消息分發給Native地圖層流程

主要爲上圖 5-->6-->7過程,以下:

  • 手勢分發層捕獲到消息,發現用戶手勢與當前熱區數據矩形沒有交集,因而將獲取的消息分發到Native地圖層。
  • 若是消息是拖動操做,則Native地圖自動識別拖動地圖消息,實現移動地圖的效果,涉及流程爲:手勢分發層-->5。
  • 若是消息是點擊操做,好比咱們想實現點擊地圖中的Marker,將消息傳遞給H5處理的功能。實現步驟爲咱們事先在添加Marker時增長一個點擊事件(Native地圖層實現),Marker被點擊時Native地圖層會派發此事件,事件消息會經過JSBridge技術從Native地圖層傳到H5層,最後H5層獲取到點擊消息。整個操做流程爲:手勢分發層-->5-->6-->7。

熱區數據的動態更新策略

由於打車業務底部的面板高度是可伸縮的,因此底部的熱區數據並非靜止不動的,須要考慮熱區數據也要隨着DOM元素的拉伸作同步調整。能夠經過在WebView H5層監控DOM的變化,DOM元素髮生變化時,獲取變化後的DOM元素位置、大小,格式化爲熱區數據,並更新到消息分發熱區數據部分。由於拉伸動做是一個連續的動畫效果,爲了高效,咱們只在動畫結束的那一刻更新熱區數據,中間過渡期不作處理。此總體流程爲:2-->3-->4。

4. 點評App中的落地實踐

4.1 手勢分發層關鍵代碼

這部分功能須要Native端同窗實現,包括iOS與Android。兩端分別在啓動App時設置三層內容,最上層是手勢觸摸事件接收層,中間是WebView層(背景設置透明),最下層是Native地圖層(如騰訊地圖SDK)。用數組記錄當前熱區數據,當手勢分發層有事件發生時,經過Touch事件獲取手指位置信息,遍歷熱區數組判斷手指位置是否與熱區的矩形相交,如相交則將消息分發給WebView層,不然分發給Native層。下邊是Android與iOS消息分發關鍵代碼:

Android分發層關鍵代碼

@Override
public boolean dispatchTouchEvent(MotionEvent event){
  if(event.getAction() == MotionEvent.ACTION_DOWN) {
    // 分發層接收到手勢觸摸消息,經過dispatchService類判斷手勢是否落在熱區內,從而肯定消息分發的對象
    this.touchHandler = dispatchService.inRegion(event) ? TouchHandler.WebView : TouchHandler.MapView;
  }
  // 分發給Native地圖層
  if(this.touchHandler == TouchHandler.MapView) {
    return this.mapView.dispatchTouchEvent(event);
  }
  // 分發給WebView H5層
  return super.dispatchTouchEvent(event);
}

iOS分發層關鍵代碼

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
   UIView *hitTestView = nil;
   // 分發層接收到手勢觸摸消息,經過pointInHotspot判斷手勢是否落在熱區內,從而肯定消息分發的對象
   if ([self pointInHotspot:point]) {
     // 分發給WebView H5層
     hitTestView = [self.WebView hitTest:point withEvent:event];
   }else{
     // 分發給Native地圖層
     hitTestView = [self.mapView hitTest:point withEvent:event];
   }
   return hitTestView;
}

4.2 WebView H5層

該層有2個功能:

  • 提供設置熱區的JS接口setHotRegion,業務可經過此接口設置屏幕中的熱區。
  • 封裝一層JS形式的地圖接口,爲上層業務提供地圖服務,該層藉助JSBridge通信橋實現H5與Native層的異步通信。

4.3 通信橋簡介

通信橋即JSBridge技術,主要實現H5與Native的信息交互,這方面的技術都已比較成熟,業界有很是多的JSBridge實現,原理也都相似,常見的有:原生對象注入到H5層、URL攔截技術,Native調用JS經常使用的內置函數stringByEvaluatingJavaScriptFromString等。美團內部有比較成熟的KNB框架,因此項目中直接使用了KNB框架。

4.4 Native地圖層

該層在地圖SDK(如騰訊地圖SDK)基礎上進行了封裝,提供一些打車業務友好的接口,如地圖基本操做、打車起終點Marker添加、接送駕司機小車動畫、地圖事件、各類Marker的信息彈窗等。

4.5 Dom元素熱區數據的自動維護技術

打車業務前端的技術棧是: Vue + VueX + Vue-Router構建的單頁系統。以下圖所示,頁面中存在不少H5元素須要添加熱區,逐個元素編寫代碼添加的話會很繁瑣,並且頁面元素的位置、大小變化時還須要同步更新熱區數據,這裏咱們使用了Vue中的directive(指令)來解決了此問題。

以上左右2圖是用戶操做時頁面展現的不一樣狀態,很明顯右圖底部卡片變高了,卡片變化同時須要同步更新對應的熱區數據,directive技術能夠很方便解決此問題,原理以下:

  • 在添加元素時,Vue指令的bind鉤子函數被觸發,此時計算出彈窗元素的大小和位置:使用getBoundingClientRect函數能夠獲取到元素的left、top、width、height等信息,將新的熱區數據經過setHotRegion函數更新到手勢分發層。
  • 在移除元素時,unbind鉤子函數被觸發,此時將熱區數據移除,這樣便實現了熱區的自動添加刪除功能了。
  • 使用指令技術很簡捷,編寫好指令的邏輯後註冊到全局,在須要動態更新熱區的元素上設置個v-hotRegion標籤就能夠了。

4.6 調試工具及測試

調試工具使用模擬器、真機均可以,開發期間咱們使用的模擬器開發,測試期間QA使用真機驗證。調試過程當中主要驗證2部分功能,分別是熱區的驗證與地圖接口驗證。

熱區驗證

主要驗證主頁面設置的熱區是否正確,包括是否能夠點擊、底部卡片是否能正常拖拉、業務功能是否正常等。由於熱區數據是一串數字,形如:[0, 0, 50, 50],沒法直觀判斷出該數據是否有誤,因而咱們開發了一個可視化工具,將設置熱區的元素都用紅色矩形高亮顯示,以下圖所示,這樣就能快速診斷出熱區數據是否有異常。工具是使用Canvas畫布實現的,畫布大小與屏幕大小徹底重合,藉助畫布就能夠將矩形熱區數據在屏幕中實時繪製出來。

地圖接口驗證

主要是編寫單元測試完成的,本項目封裝了50多個地圖接口,每一個接口都編寫單測用例,觀察入參、出參、控制檯輸出結果,地圖展現效果是否正確等。測試主要在iOS模擬器中完成,這樣方便在控制檯打印一些調試信息進行診斷。

5. 上線效果

該框架在大衆點評App中上線後地圖體驗明顯提高,主要有體如今如下幾個方面:

  • 地圖的操做體驗,如地圖移動、縮放明顯好於H5地圖,用戶利用Native地圖選擇起終點、下單叫車、接送駕小車動畫效果更加流暢。
  • 首屏地圖數據指標也有顯著提高,以下表所示:

  • 目前線上運行穩定,上線2月期間,Crash數量爲個位數,Crash率遠低於0.1‰。
  • 框架上線後,大衆點評App中業務迭代能夠按照H5節奏上線,實現隨時發版的開發效率。

Native地圖層代碼接口穩定、功能豐富,基本知足地圖場景的業務需求。只需首次跟版發佈,後續只須要迭代H5的業務邏輯便可。

6. 本文小結

本文將WebView與Native地圖組件疊加到一塊兒,實現了用戶手勢事件智能分發的機制,解決了WebView與Native地圖在同一頁面內佈局困難的問題。這種融合機制爲打車業務提高迭代效率同時保障地圖體驗提供了一種有效的途徑,平常業務功能上線採用H5技術迭代,Native地圖做爲不常更新的基礎能力首次發版時安裝到用戶手機上,實現業務需求隨時發版的能力,再也不受各大應用商店的限制,用戶操做地圖的體驗也更加流暢。該融合框架適合如下業務場景:

  • 業務中使用了地圖功能,並對地圖的加載、操做體驗等有較高要求的業務。
  • 業務屬於Hybrid業務,而且H5頁面與地圖在同一頁面內佈局的功能。
  • 若是你的業務是基於多個WebView與Native地圖構建的系統,很是建議你瞭解下此文章。

7. 做者簡介

美團打車技術部終端研發中心,加鵬、張斌、楊睿、邱博、海峯等。

8. 招聘信息

美團打車技術部終端研發中心誠招高級前端開發工程師、前端開發專家、高級iOS工程師、高級Android工程師。咱們爲美團點評用戶提供優質的打車服務,是本地生活吃喝玩樂行的重要環節。歡迎各位小夥伴的加入,共同打造極致出行產品。感興趣的同窗可投遞簡歷至:tech@meituan.com(郵件標題註明:美團打車技術部終端研發中心)

想閱讀更多技術文章,請關注美團技術團隊(meituantech)官方微信公衆號。

相關文章
相關標籤/搜索