前言
基于前面的三篇,我們的Hybird框架基本搭建完成了莉测,本篇在《寫一個(gè)易于維護(hù)使用方便性能可靠的Hybrid框架(三)—— 配置插件》的基礎(chǔ)上做了一些優(yōu)化颜骤,后續(xù)又做了UIWebView的兼容。當(dāng)下的跨平臺方案很多捣卤,weex
忍抽、RN
到flutter
層出不窮。那么對于WebView
的探究是否仍有必要董朝?實(shí)際上我們可以探究一下他們的根本梯找,或許就不會有疑惑了∫娼В跨平臺方案旨在節(jié)約成本,快速更新迭代驯鳖,甚至達(dá)到熱更新的能力闲询。那么WebView
面向的是誰呢,是整個(gè)前端開發(fā)者浅辙,構(gòu)建web應(yīng)用目前來看依舊是效率最快扭弧、范圍最廣、熱更新能力最強(qiáng)的不二之選记舆。市面上的App幾乎都無法逃離WebView
鸽捻,從《支付寶移動端動態(tài)化方案實(shí)踐》可以看出,支付寶也有一套自己的解決方案Nebula 框架
泽腮,其實(shí)不止支付寶御蒲,所有的App自始至終都會有一套自己的WebView
框架,與前面提到的跨端技術(shù)并不沖突诊赊,屬于并駕齊驅(qū)厚满。
那么今天要說的就是如何構(gòu)建一個(gè)WebView的Hybrid框
架,并讓它獨(dú)立于項(xiàng)目中碧磅,像AFN
碘箍、SD
一樣存在于你的項(xiàng)目中,也并不會關(guān)聯(lián)你的業(yè)務(wù)鲸郊,像支付寶的Nebula
一樣丰榴,讓它成為你項(xiàng)目組件的一部分。
接下來會從下面四個(gè)方面進(jìn)行逐步分析秆撮,盡量多點(diǎn)干貨四濒。
目錄
- 現(xiàn)狀分析
- 治理方案
- 框架構(gòu)建
- 總結(jié)
一、現(xiàn)狀分析
前言部分基本闡述了當(dāng)下為什么要構(gòu)建WebView框架,就目前來看峻黍,每個(gè)項(xiàng)目應(yīng)該都是前端和客戶端混合開發(fā)复隆,純原生的項(xiàng)目已經(jīng)退出歷史了。就項(xiàng)目來看姆涩,h5構(gòu)建在客戶端內(nèi)自然少不了要與客戶端打交道挽拂。相信很多App還停留在使用原始攔截的方式進(jìn)行JS和Native端的交互,通過定義好的某個(gè)協(xié)議進(jìn)行攔截JS請求骨饿。這樣的方式雖然簡單亏栈,但缺點(diǎn)太多。
首先從技術(shù)層面來看宏赘,這樣需要做隊(duì)列控制連續(xù)的JS調(diào)用绒北,防止通信丟失,這也是一個(gè)復(fù)雜的工作察署,而且效率低闷游,其次通過假請求攔截,一旦請求參數(shù)拼接過于復(fù)雜還會產(chǎn)生一些其他的副作用贴汪,例如url過長參數(shù)無法被攔截脐往,參數(shù)拼接后字符串截取出錯等等。
備注一下:url攔截處理參數(shù)并非都是使用的這種方式扳埂,例如大名鼎鼎的《Cordova》和《WebViewJavaScriptBridge》都是使用的另外一種方式:曲線救國业簿,增加一層JS側(cè)來處理參數(shù)調(diào)度問題,而非直接攔截參數(shù)阳懂。
其次我們從業(yè)務(wù)的層面考慮梅尤,當(dāng)需要通信的需求越來越多,WebView框架內(nèi)的代碼是否也會變得越來越冗余岩调,摻雜的業(yè)務(wù)是否會變得越來越多巷燥,耦合是否越來越高等等。當(dāng)我們有新的需求進(jìn)來了是否要繼續(xù)讓WebView框架
變得冗余号枕?復(fù)用就更不可能了矾湃。
相信現(xiàn)在很多App在這一塊還停留在上面的例子中,那么怎么解決這些問題堕澄?首先我們應(yīng)該要有個(gè)好的通信方案邀跃,一個(gè)前衛(wèi)的,先進(jìn)的通信方案可以比作框架的心臟蛙紫。
下面我們繼續(xù)分析一下現(xiàn)在有什么通信方案更適合我們拍屑。
二、治理方案
治理方案這一塊可以看下我的另一篇文章《寫一個(gè)易于維護(hù)使用方便性能可靠的Hybrid框架(一)—— 思路構(gòu)建》坑傅,主要講了框架的構(gòu)建思路僵驰,后兩篇是對思路進(jìn)行了延伸和進(jìn)一步的優(yōu)化。
目前看來在通信選擇這一塊有很多,簡單闡明一下優(yōu)缺點(diǎn):
JS調(diào)用客戶端:
- 1.假跳轉(zhuǎn)攔截:也就是上面提到的蒜茴,這應(yīng)該是第一個(gè)被pass掉的方案星爪,因?yàn)樗话踩【湍壳爸髁鞯拈_源來看粉私,不論是大名鼎鼎的《Cordova》還是《WebViewJavaScriptBridge》都對它做了大量的操作顽腾,大量的操作,關(guān)于Cordova的操作可以參考我之前的文章《Cordova框架的“曲線救國”》
- 2.彈窗攔截:UIWebView不支持使用彈窗攔截JS诺核。WKWebView支持confirm()/prompt()彈窗攔截抄肖,同步返回。
- 3.JavaScriptCore框架注入:這是一個(gè)異常強(qiáng)大的框架窖杀,iOS7開始支持漓摩,強(qiáng)大到RN都是依托于此,充滿了很多黑魔法入客。具體它的使用可以參考《深入淺出 JavaScriptCore》管毙,但是遺憾的是只有UIWebView支持它。WKWebView無法通過kvc獲取JSContext桌硫,所以WK并不支持夭咬。
- 4.Messagehandler注入:addScriptMessageHandler:函數(shù)誕生于iOS8,伴隨著WKWebView開放給開發(fā)者的鞍泉,所以遺憾的是它只有WKWebView支持,但我把它理解為蘋果通信這一塊的親兒子肮帐,畢竟蘋果爸爸出品咖驮。
上面列出了所有的JS打到Native端的通信途徑,如果我們必須要選擇一個(gè)方案來實(shí)施训枢,優(yōu)先選擇下面兩種:
- WKWebView首選Messagehandler注入:
[webView.configuration.userContentController addScriptMessageHandler:self name:@"WKJSBridge"];
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
if ([message.body isKindOfClass:[NSArray class]]) {
[_webViewhandleFactory handleMsgCommand:message.body];
}
}
JS側(cè)的調(diào)用也會非常簡單托修,通過客戶端注入的WKJSBridge
就可以構(gòu)建通信了:
window.webkit.messageHandlers.WKJSBridge.postMessage()
上面的代碼就是Messagehandler方式的通信過程了,很簡單恒界,從代碼中可以很清楚的看到什么是親兒子的通信睦刃,再對比下曲線救國
式的通信,對比就灰常明顯了十酣。WKJSBridge
就是WKWebView注入的JS函數(shù)涩拙。實(shí)際上客戶端就做了這么點(diǎn)工作就可以了,message.body
可以是任意id類型對象耸采,取決于JS端給客戶端傳遞的是什么類型兴泥,demo中傳遞的是NSArray
類型。
- UIWebView首選JavaScriptCore框架:
原因JavaScriptCore
功能異常強(qiáng)大虾宇,可以直接給JS注入一個(gè)函數(shù)讓它調(diào)用搓彻,也可以直接給JS注入一個(gè)OC對象讓JS使用,充滿黑科技。不論是RN旭贬,還是Weex怔接,都是基于此來構(gòu)建的通信。具體使用可以通過《WKJavaScriptBridge》深入探究一下稀轨。
客戶端主動調(diào)用JS:
- 1.evaluatingJavaScript:函數(shù) :只支持UIWebView扼脐,同步回調(diào)。
- 2.evaluateJavaScript:completionHandler:函數(shù) :只支持WKWebView靶端,異步回調(diào)谎势。
關(guān)于客戶端回調(diào)JS方式毋庸置疑,各自選各自的就可以了杨名。
通信的選擇這塊就確定了:
- WKWebView:
Messagehandler注
入和evaluateJavaScript:completionHandler:
回調(diào)脏榆。 - UIWebView:
JavaScriptCore框架注入
和evaluatingJavaScript:
回調(diào)。
那么接下來看一下對于業(yè)務(wù)過多導(dǎo)致冗余該怎么處理台谍。
這一塊前面的文章也有提到须喂,可以看看《寫一個(gè)易于維護(hù)使用方便性能可靠的Hybrid框架(二)—— 插件化》了解一下。插件化構(gòu)建趁蕊,讓每一個(gè)業(yè)務(wù)功能都成為一個(gè)module坞生,一個(gè)插件。插件是什么意思掷伙,就是獨(dú)立
J羌骸!與除了我們Web框架以外其他的類無任何耦合
任柜,它只是被框架管理著卒废,靜靜的在那里工作,刪除了項(xiàng)目依舊Build
V娴亍摔认!插件制作完畢拖到項(xiàng)目可以直接使用
。這樣就讓業(yè)務(wù)模塊完全分離
宅粥,全部剝離框架参袱,新的需求只需要建立新的模塊即可,不需要動Web框架秽梅。
截圖中的Fetch
可以理解為JS的請求要客戶端來做這種功能抹蚀,Device
可以理解為JS想要客戶端的設(shè)備信息功能等等等...那么有新需求無限擴(kuò)充這種模塊就好了。清晰一目了然企垦。細(xì)節(jié)請下載項(xiàng)目進(jìn)行查看况鸣。關(guān)于插件注冊看一下我前面的文章配置插件。經(jīng)過這樣的處理竹观,是不是我們的代碼就一目了然了镐捧,易維護(hù)潜索,可拓展,重點(diǎn)是無耦合
6础竹习!
到這里上面提到的問題就都得到解決了,基于前面的幾篇文章Coding了一個(gè)Hybrid框架《WKJavaScriptBridge》列牺,目前正在往項(xiàng)目中推廣整陌,大家覺得有幫助歡迎Star,有問題歡迎Issue瞎领。關(guān)于WKWebView的各種坑可以看一下WKWebView這篇文章泌辫。下面說一下WKJavaScriptBridge項(xiàng)目的主要構(gòu)建思路。
三九默、框架構(gòu)建
框架地址:https://github.com/GitWangKai/WKJavaScriptBridge
框架結(jié)構(gòu):
框架的主要特點(diǎn):兼容了UIWebView&WKWebView震放,插件化了交互業(yè)務(wù)模塊,當(dāng)然還有一些其他特性參照《README.md》驼修。
構(gòu)建原則:解耦殿遂,業(yè)務(wù)分離,低代碼浸入乙各,高可拓展墨礁,高復(fù)用,易集成耳峦。
框架類圖:
UIWebView和WKWebView兼容恩静,由業(yè)務(wù)自定義即可,框架不關(guān)心傳入的是那種類型蹲坷,皆可處理驶乾。
項(xiàng)目構(gòu)建主要基于上面提到的痛點(diǎn)問題進(jìn)行了處理,目前為0.0.1版本冠句,后續(xù)會繼續(xù)擴(kuò)充轻掩。具體實(shí)現(xiàn)參照源碼幸乒,如果覺得有幫助懦底,歡迎Star。
四罕扎、總結(jié)
文末做個(gè)總結(jié)聚唐,目前上面的方案只是為我們項(xiàng)目Hybrid
打了個(gè)基石,后續(xù)還會有很多很多工作需要延伸腔召。至少目前Hybrid在WebView
處理這一塊的組件已經(jīng)出爐了杆查。后續(xù)會基于此,擴(kuò)充離線包臀蛛、JS側(cè)插件化處理亲桦、引入Flutter跨端技術(shù)崖蜜、構(gòu)建小程序框架
。接下來我會構(gòu)建第二個(gè)功能:離線包組件
客峭。
敬請期待豫领。
如果由任何疑問或者建議歡迎issue,讓它變得更好舔琅。