Hybrid開發是現在的主流形式,對於業務快速迭代的公司尤其重要。曾將在鞋廠接觸了很多關於Hybrid的理念,在這里分享一些Hybrid框架思想。
Hybrid框架包括Native與H5的通信,WebView的管理等,這里主要介紹通信。
文章主要分為兩個部分,第一部分介紹Hybrid與H5通信的幾種方式,第二部分分析了開源框架的具體做法。
第一部分 Hybrid與H5通信
Hybrid與H5通信實現方式有很多種,有基於url攔截的,也有基於prompt攔截的。
最后分析的這個框架和PhoneGap一樣采用prompt攔截,但內部處理機制沒有PhoneGap復雜,暫時對PhoneGap不是完全了解,就不裝B了。
H5與Native通信,現在采用最多的方式是依賴中間過渡的WebView,其他的不了解。
基於對Hybrid的了解,就分H5調用Native和Native通知H5。下面來細說這兩點。
1.H5調用Native
這種方式主要是需要Native宿主環境通過WebView來提供一些H5調用的接口方法。
如果采用url攔截的,也就是通過一個隱藏iframe或者修改location發起請求,比如bridge://service/method?params&callback,可以在webview加載時獲取到該url,並針對url信息分析對應到Native中的某個service類的某個method方法。
如果采用prompt攔截的,比如prompt(service,method,params,callback),原理與url方式差不多,不過是在H5發起prompt請求,webview截獲到這個prompt中的參數,調用Native中對應的某個service類的某個method方法。
這兩種方式一般會與一個Bridge.js配合,Bridge.js封裝了bridge://service/method?params&callback的構造,或prompt(service,method,params,callback)的請求,提供H5良好的訪問接口。
當H5端調用某個方法時,將對應的參數和回調封裝成url或prompt的形式,然后請求webview,webview截獲url或prompt,請求本地服務獲取數據后,通過注冊在window對象上的callback將請求結果返回給H5。
這兩種方式的開源庫可參考:jsbridge-to-cocoa(url+bridge.js) safe-java-js-webview-bridge(prompt)
針對這兩種基本方式可擴展,比如某所是直接采用了url+bridge這種方式,而鞋廠則針對性的做出些調整(后面針對性的介紹),還有后面介紹的safe-java-js-webview-bridge則與PhoneGap類似,消除了H5對Bridge.js的可見性,通過反射Native提供的service自動構造Bridge.js並注入到WebView中。
至於上面兩種方式及其擴展的好壞之分,主要看設計上如何使H5調用變得簡單則好,盡量降低Native與H5的耦合,分清構造Bridge.js的職責。
2.Native通知H5
這種方式主要是H5將某些監聽事件(如webview下拉刷新、native推送)綁定到window上,當Native需要調用H5時,可以通過webview中注冊的這些事件回調通知H5。
Native通知H5的方式比H5調用Native來的簡單,不過在項目中如何將二者結合起來,提供統一的調用接口則需要良好的設計。
如果需要完成H5與Native的相互訪問,基本上采用上面兩種方法即可完成,但如果要封裝的對H5調用接口友好,則需要在設計上下功夫,這就是仁者見仁智者見智的事情。
后續會分別補充某所和鞋廠各自對Bridge.js的封裝思想。//TODO
第二部分 開源框架分析
1.iOS開源框架 jsbridge-to-cocoa
先來看看jsbridge-to-cocoa的源碼結構,因為不存在太多的設計思想,僅僅是上述方式的一個實現過程。
采用url攔截的方式實現H5調用Native,但調用后沒有回調的過程,而且還未實現Native通知H5的過程。(可能理解有偏差,大神勿噴)
下面說說這個框架的基本思想,Bridge.js中包含了供H5和Native使用的方法,分兩步:
1. H5通過調用AddObject添加請求的參數和回調,通過SendObject封裝的url來觸發webview攔截;
2. Native中的webview攔截后,會分析url中的請求參數,調用本地服務,完成本地功能后會調用Bridge提供的接口,調用H5的回調
下面直接看看時序圖,也比較易於理解。
注:描述過程和截圖中都含有紅色部分,是針對該框架的弱點提供的補充,即可保證H5訪問Native后能回調H5的過程。
2.Android開源框架 safe-java-js-webview-bridge
抽空看了了下safe-java-js-webview-bridge的源碼,整理了一份類之間的調用關系圖。
值得推薦的是這個庫屏蔽了H5對Bridge.js的可見性,而且Bridge.js是通過對Native中對外公開的類進行反射生成的,提高了復用性。
不過也有其缺點,Native提供給H5的方法都封裝在一個Bridge.js中,如果Native需要暴露給H5的功能模塊增多時,且需要按模塊進行細分時,Bridge.js則顯得有點模糊。
這個問題只需要對其原理熟悉,改造成支持多模塊的成本也不大。后續補充源碼連接,還在改造中。//TODO
注:這個庫中Bridge.js這個文件名是不存在的,可自行指定,這里為了方便理解,所以采用Bridge.js。
下面說說開源庫safe-java-js-webview-bridge的基本思路,分三步:
1.在native端編寫調用本地功能的class(如HostJsScope.java),在初始化WebviewChromeClient時根據該class(在JsCallJava構造函數中)反射動態生成js代碼;
2.將動態生成的js代碼通過webview.loadUrl觸發的onProgressChanged注入到webview中,供前端可調用;
3.在前端調用HostJsScope對應的接口,出發webview的onPrompt事件,進而調用本地HostJsScope方法,如果是同步且有返回值,通過prompt返回值返回,如果是異步,則反射調用JsCallback將數據返回前端。
先上圖,后面逐步分析調用關系。(由於對UML時序圖不甚了解,原諒圖中的錯誤)
根據截圖可以清晰的看到三個步驟的調用過程,如果有興趣的可以拿源碼對比該截圖進行分析。
通過對以上兩個開源框架的分析,可以理解H5調用Native並回調H5的通信過程,但二者都為對Native通知H5的通信實現,不過這部分實現也比較簡單。原理上面也解釋過了,通過截圖來描述下。
Hybrid框架中H5與Native相互通信的過程基本如此,不過很多原理細節未做過多描述,如果興趣的同學可以留言一起討論。