前言
當下的跨平臺方案很多,weex
、RN
到flutter
層出不窮。那麼對於WebView
的探究是否仍有必要?實際上我們可以探究一下他們的根本,或許就不會有疑惑了。跨平臺方案旨在節約成本,快速更新迭代,甚至達到熱更新的能力。那麼WebView
面向的是誰呢,是整個前端開發者,構建web應用目前來看依舊是效率最快、範圍最廣、熱更新能力最強的不二之選。市面上的App幾乎都無法逃離WebView
,從支付寶移動端動態化方案實踐可以看出,支付寶也有一套自己的解決方案Nebula 框架
,其實不止支付寶,所有的App自始至終都會有一套自己的WebView
框架,與前面提到的跨端技術並不衝突,屬於並駕齊驅。
那麼今天要說的就是如何構建一個WebView的Hybrid框
架,並讓它成為你專案獨立的一部分,像AFN
、SD
一樣存在於你的專案中,也並不會關聯你的業務,像支付寶的Nebula
一樣,讓它成為你專案元件的一部分。
接下來會從下面四個方面進行逐步分析,儘量多點乾貨。
目錄
- 現狀分析
- 治理方案
- 框架構建
- 總結
一、現狀分析
前言部分基本闡述了當下為什麼要構建WebView框架,就目前來看,每個專案應該都是前端和客戶端混合開發,純原生的專案已經退出歷史了。就專案來看,h5構建在客戶端內自然少不了要與客戶端打交道。相信很多App還停留在使用原始攔截的方式進行JS和Native端的互動,通過定義好的某個協議進行攔截JS請求。這樣的方式雖然簡單,但缺點太多。
首先從技術層面來看,這樣需要做佇列控制連續的JS呼叫,防止通訊丟失,這也是一個複雜的工作,而且效率低,其次通過假請求攔截,一旦請求引數拼接過於複雜還會產生一些其他的副作用,例如url過長引數無法被攔截,引數拼接後字串擷取出錯等等。
其次我們從業務的層面考慮,當需要通訊的需求越來越多,WebView框架內的程式碼是否也會變得越來越冗餘,摻雜的業務是否會變得越來越多,耦合是否越來越高等等。當我們有新的需求進來了是否要繼續讓WebView框架
變得冗餘?複用就更不可能了。
相信現在很多App在這一塊還停留在上面的例子中,那麼怎麼解決這些問題?首先我們應該要有個好的通訊方案,一個前衛的,先進的通訊方案可以比作框架的心臟。
下面我們繼續分析一下現在有什麼通訊方案更適合我們。
二、治理方案
治理方案這一塊可以看下我的另一篇文章寫一個易於維護使用方便效能可靠的Hybrid框架(一)—— 思路構建,主要講了框架的構建思路,後兩篇是對思路進行了延伸。
目前看來在通訊選擇這一塊有很多,簡單闡明一下優缺點:
JS呼叫客戶端:
- 1.假跳轉攔截:也就是上面提到的,這應該是第一個被pass掉的方案,因為它不安全!就目前主流的開源來看,不論是大名鼎鼎的Cordova還是WebViewJavaScriptBridge都對它做了大量的操作,大量的操作...
- 2.彈窗攔截:UIWebView不支援使用彈窗攔截JS。WKWebView支援confirm()/prompt()彈窗攔截,同步返回。
- 3.JavaScriptCore框架注入:這是一個異常強大的框架,iOS7開始支援,強大到RN都是依託於此,充滿了很多黑魔法。具體它的s你用可以參考深入淺出 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];
}
}
複製程式碼
以上程式碼摘自SHRMJavaScriptBridge。Messagehandler的具體使用不在本篇範圍,具體使用可以參照SHRMJavaScriptBridge框架。
從程式碼中可以很清楚的看到親兒子的通訊,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框架。
截圖來源於SHRMJavaScriptBridge專案。
截圖中的Fetch
可以理解為JS的請求要客戶端來做這種功能,Device
可以理解為JS想要客戶端的裝置資訊功能等等等...那麼有新需求無限擴充這種模組就好了。清晰一目瞭然。細節請下載專案進行檢視。關於外掛註冊看一下我前面的文章配置外掛。經過這樣的處理,是不是我們的程式碼就一目瞭然了,易維護,可擴充,重點是無耦合
!!
到這裡上面提到的問題就都得到解決了,基於前面的幾篇文章Coding了一個Hybrid框架SHRMJavaScriptBridge,目前正在往專案中推廣,大家覺得有幫助歡迎Star,有問題歡迎Issue。關於WKWebView的各種坑可以看一下WKWebView這篇文章。下面說一下SHRMJavaScriptBridge專案的主要構建思路。
三、框架構建
框架地址:github.com/GitWangKai/…
框架結構:
框架的主要特點:相容了UIWebView&WKWebView,外掛化了互動業務模組,當然還有一些其他特性參照README.md。
構建原則:解耦,業務分離,低程式碼浸入,高可擴充,高複用,易整合。
框架類圖:
UIWebView和WKWebView相容,由業務自定義即可,框架不關心傳入的是那種型別,皆可處理。
專案構建主要基於上面提到的痛點問題進行了處理,目前為0.0.1版本,後續會繼續擴充。具體實現參照原始碼,如果覺得有幫助,歡迎Star。
四、總結
文末做個總結,目前上面的方案只是為我們專案Hybrid
打了個基石,後續還會有很多很多工作需要延伸。至少目前Hybrid在WebView
處理這一塊的元件已經出爐了。後續會基於此,擴充離線包、JS側外掛化處理、引入Flutter跨端技術、構建小程式框
架。接下來我會構建第二個功能:離線包元件
。
敬請期待。
最後再次奉上Demo地址,如果對你有幫助,star鼓勵下謝謝。如果由任何疑問或者建議歡迎issue,讓它變得更好。