寫一個易於維護使用方便性能可靠的Hybrid框架(四)—— 框架構建

《寫一個易於維護使用方便性能可靠的Hybrid框架(一)—— 思路構建》

《寫一個易於維護使用方便性能可靠的Hybrid框架(二)—— 插件化》

《寫一個易於維護使用方便性能可靠的Hybrid框架(三)—— 配置插件》

《寫一個易於維護使用方便性能可靠的Hybrid框架(四)—— 框架構建》

前言

基於前面的三篇,咱們的Hybird框架基本搭建完成了,本篇在《寫一個易於維護使用方便性能可靠的Hybrid框架(三)—— 配置插件》的基礎上作了一些優化,後續又作了UIWebView的兼容。當下的跨平臺方案不少,weexRNflutter層出不窮。那麼對於WebView的探究是否仍有必要?實際上咱們能夠探究一下他們的根本,或許就不會有疑惑了。跨平臺方案旨在節約成本,快速更新迭代,甚至達到熱更新的能力。那麼WebView面向的是誰呢,是整個前端開發者,構建web應用目前來看依舊是效率最快、範圍最廣、熱更新能力最強的不二之選。市面上的App幾乎都沒法逃離WebView,從《支付寶移動端動態化方案實踐》能夠看出,支付寶也有一套本身的解決方案Nebula 框架,其實不止支付寶,全部的App自始至終都會有一套本身的WebView框架,與前面提到的跨端技術並不衝突,屬於並駕齊驅。前端

那麼今天要說的就是如何構建一個WebView的Hybrid框架,並讓它獨立於項目中,像AFNSD同樣存在於你的項目中,也並不會關聯你的業務,像支付寶的Nebula同樣,讓它成爲你項目組件的一部分。ios

接下來會從下面四個方面進行逐步分析,儘可能多點乾貨。git

目錄

  • 現狀分析
  • 治理方案
  • 框架構建
  • 總結

1、現狀分析

前言部分基本闡述了當下爲何要構建WebView框架,就目前來看,每一個項目應該都是前端和客戶端混合開發,純原生的項目已經退出歷史了。就項目來看,h5構建在客戶端內天然少不了要與客戶端打交道。相信不少App還停留在使用原始攔截的方式進行JS和Native端的交互,經過定義好的某個協議進行攔截JS請求。這樣的方式雖然簡單,但缺點太多。github

首先從技術層面來看,這樣須要作隊列控制連續的JS調用,防止通訊丟失,這也是一個複雜的工做,並且效率低,其次經過假請求攔截,一旦請求參數拼接過於複雜還會產生一些其餘的反作用,例如url過長參數沒法被攔截,參數拼接後字符串截取出錯等等。web

備註一下:url攔截處理參數並不是都是使用的這種方式,例如大名鼎鼎的《Cordova》《WebViewJavaScriptBridge》都是使用的另一種方式:曲線救國,增長一層JS側來處理參數調度問題,而非直接攔截參數。apache

其次咱們從業務的層面考慮,當須要通訊的需求愈來愈多,WebView框架內的代碼是否也會變得愈來愈冗餘,摻雜的業務是否會變得愈來愈多,耦合是否愈來愈高等等。當咱們有新的需求進來了是否要繼續讓WebView框架變得冗餘?複用就更不可能了。小程序

相信如今不少App在這一塊還停留在上面的例子中,那麼怎麼解決這些問題?首先咱們應該要有個好的通訊方案,一個前衛的,先進的通訊方案能夠比做框架的心臟。安全

下面咱們繼續分析一下如今有什麼通訊方案更適合咱們。weex

2、治理方案

治理方案這一塊能夠看下個人另外一篇文章《寫一個易於維護使用方便性能可靠的Hybrid框架(一)—— 思路構建》,主要講了框架的構建思路,後兩篇是對思路進行了延伸和進一步的優化。架構

目前看來在通訊選擇這一塊有不少,簡單闡明一下優缺點:

JS調用客戶端:

  • 1.假跳轉攔截:也就是上面提到的,這應該是第一個被pass掉的方案,由於它不安全!就目前主流的開源來看,不管是大名鼎鼎的《Cordova》仍是《WebViewJavaScriptBridge》都對它作了大量的操做,大量的操做,關於Cordova的操做能夠參考我以前的文章《Cordova框架的「曲線救國」》
  • 2.彈窗攔截:UIWebView不支持使用彈窗攔截JS。WKWebView支持confirm()/prompt()彈窗攔截,同步返回。
  • 3.JavaScriptCore框架注入:這是一個異常強大的框架,iOS7開始支持,強大到RN都是依託於此,充滿了不少黑魔法。具體它的使用能夠參考《深刻淺出 JavaScriptCore》,可是遺憾的是隻有UIWebView支持它。WKWebView沒法經過kvc獲取JSContext,因此WK並不支持。
  • 4.Messagehandler注入:addScriptMessageHandler:函數誕生於iOS8,伴隨着WKWebView開放給開發者的,因此遺憾的是它只有WKWebView支持,但我把它理解爲蘋果通訊這一塊的親兒子,畢竟蘋果爸爸出品。

上面列出了全部的JS打到Native端的通訊途徑,若是咱們必需要選擇一個方案來實施,優先選擇下面兩種:

  • WKWebView首選Messagehandler注入:
[webView.configuration.userContentController addScriptMessageHandler:self name:@"SHRMWKJSBridge"];
複製代碼
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    if ([message.body isKindOfClass:[NSArray class]]) {
        [_webViewhandleFactory handleMsgCommand:message.body];
    }
}

複製代碼

JS側的調用也會很是簡單,經過客戶端注入的SHRMWKJSBridge就能夠構建通訊了:

window.webkit.messageHandlers.SHRMWKJSBridge.postMessage()
複製代碼

上面的代碼就是Messagehandler方式的通訊過程了,很簡單,從代碼中能夠很清楚的看到什麼是親兒子的通訊,再對比下曲線救國式的通訊,對比就灰常明顯了。SHRMWKJSBridge就是WKWebView注入的JS函數。實際上客戶端就作了這麼點工做就能夠了,message.body能夠是任意id類型對象,取決於JS端給客戶端傳遞的是什麼類型,demo中傳遞的是NSArray類型。

  • UIWebView首選JavaScriptCore框架:

緣由JavaScriptCore功能異常強大,能夠直接給JS注入一個函數讓它調用,也能夠直接給JS注入一個OC對象讓JS使用,充滿黑科技。不管是RN,仍是Weex,都是基於此來構建的通訊。具體使用能夠經過《SHRMJavaScriptBridge》深刻探究一下。

客戶端主動調用JS:

  • 1.evaluatingJavaScript:函數 :只支持UIWebView,同步回調。
  • 2.evaluateJavaScript:completionHandler:函數 :只支持WKWebView,異步回調。

關於客戶端回調JS方式毋庸置疑,各自選各自的就能夠了。

通訊的選擇這塊就肯定了:

  • WKWebView:Messagehandler注入和evaluateJavaScript:completionHandler:回調。
  • UIWebView:JavaScriptCore框架注入evaluatingJavaScript:回調。

那麼接下來看一下對於業務過多致使冗餘該怎麼處理。

這一塊前面的文章也有提到,能夠看看《寫一個易於維護使用方便性能可靠的Hybrid框架(二)—— 插件化》瞭解一下。插件化構建,讓每個業務功能都成爲一個module,一個插件。插件是什麼意思,就是獨立!!與除了咱們Web框架之外其餘的類無任何耦合,它只是被框架管理着,靜靜的在那裏工做,刪除了項目依舊Build!!插件製做完畢拖到項目能夠直接使用。這樣就讓業務模塊徹底分離,所有剝離框架,新的需求只須要創建新的模塊便可,不須要動Web框架。

截圖中的Fetch能夠理解爲JS的請求要客戶端來作這種功能,Device能夠理解爲JS想要客戶端的設備信息功能等等等...那麼有新需求無限擴充這種模塊就行了。清晰一目瞭然。細節請下載項目進行查看。關於插件註冊看一下我前面的文章配置插件。通過這樣的處理,是否是咱們的代碼就一目瞭然了,易維護,可拓展,重點是無耦合!!

到這裏上面提到的問題就都獲得解決了,基於前面的幾篇文章Coding了一個Hybrid框架《SHRMJavaScriptBridge》,目前正在往項目中推廣,你們以爲有幫助歡迎Star,有問題歡迎Issue。關於WKWebView的各類坑能夠看一下WKWebView這篇文章。下面說一下SHRMJavaScriptBridge項目的主要構建思路。

3、框架構建

框架地址:github.com/GitWangKai/…

框架結構:

框架的主要特色:兼容了UIWebView&WKWebView,插件化了交互業務模塊,固然還有一些其餘特性參照《README.md》

構建原則:解耦,業務分離,低代碼浸入,高可拓展,高複用,易集成。

框架類圖:

UIWebView和WKWebView兼容,由業務自定義便可,框架不關心傳入的是那種類型,皆可處理。

項目構建主要基於上面提到的痛點問題進行了處理,目前爲0.0.1版本,後續會繼續擴充。具體實現參照源碼,若是以爲有幫助,歡迎Star。

4、總結

文末作個總結,目前上面的方案只是爲咱們項目Hybrid打了個基石,後續還會有不少不少工做須要延伸。至少目前Hybrid在WebView處理這一塊的組件已經出爐了。後續會基於此,擴充離線包、JS側插件化處理、引入Flutter跨端技術、構建小程序框架。接下來我會構建第二個功能:離線包組件

敬請期待。

若是由任何疑問或者建議歡迎issue,讓它變得更好。