? ? ? ? 前段時(shí)間將項(xiàng)目中的Cordova做了一下升級(jí),由于項(xiàng)目本身比較大,涉及到的Native和H5交互的模塊又非常多,所以整個(gè)項(xiàng)目改造下來(lái)還是發(fā)了點(diǎn)時(shí)間的,廢話不多說(shuō),直接進(jìn)入主題,整個(gè)項(xiàng)目改造大致可以分為下面幾個(gè)階段:
1.集成最新版Cordova,也就是4.0.0版本(這個(gè)版本在設(shè)計(jì)架構(gòu)上完全區(qū)別于老版Cordova)
2.研究新Cordova框架(類似使用了構(gòu)建者模式+運(yùn)行時(shí)機(jī)制,下面細(xì)聊)
3.涉及到Cordova的地方整改,模塊的整合,重構(gòu)
首先,如何集成Cordova 4.4.0:
? ? ? ?從Adobe收購(gòu)了Nitobi Software和它的PhoneGap產(chǎn)品,然后宣布這個(gè)移動(dòng)開發(fā)框架將會(huì)繼續(xù)開源,并把它提交到Apache Incubator,以便完全接受ASF的管治,導(dǎo)致項(xiàng)目無(wú)法直接通過(guò)Cocoapods集成,唯一的辦法就是通過(guò)Shell創(chuàng)建一個(gè)Cordova項(xiàng)目,然后將整個(gè)項(xiàng)目中的有用資源取出來(lái),丟進(jìn)自己的工程里面,這樣,一些配置就得自己手動(dòng)完成(配置也很簡(jiǎn)單,繼續(xù)看)
? ? ? ?扯了半天,終于進(jìn)入主題了,集成Cordova是通過(guò)命令行來(lái)做的,但是必須先安裝Cordova命令工具,而這個(gè)命令工具是在npm命令工具下的,這就要求先安裝node.js(www.runoob.com/nodejs/nodejs-install-setup.html),里面包含了安裝npm工具的命令,這不是重點(diǎn),安裝的過(guò)程自己看看,也很簡(jiǎn)單。
現(xiàn)在假設(shè)已經(jīng)安裝好了npm工具,直接執(zhí)行以下幾個(gè)命令創(chuàng)建一個(gè)iOS的Cordova項(xiàng)目:
$ mkdir Cordova ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #新建文件夾?
$ cd Cordova
$ cordova create hello com.example.hello HelloWorld ?#創(chuàng)建一個(gè)cordova項(xiàng)目
$ cd hello
$ cordova platform add ios ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?#指定生成iOS平臺(tái)的代碼項(xiàng)目
$ cordova plugin add cordova-plugin-wkwebview-engine #添加WK插件
這樣就創(chuàng)建了一個(gè)新版Cordova項(xiàng)目,接下來(lái)就將需要的文件拖到自己的項(xiàng)目里面,見圖:

拖完后,加入到編譯環(huán)境中,此時(shí)項(xiàng)目已經(jīng)包含了Cordova了,但是這個(gè)還不夠,因?yàn)镃ordova本身就是H5交互Native的橋梁,Native支持了,還得H5也支持,這里需要注意的地方是新版的cordova.js能夠支持舊版的cordova,但是舊版的cordova.js絕不支持新版(向下兼容了),所以自己項(xiàng)目中已經(jīng)集成了舊Cordova的,必須要求H5同胞們也得升級(jí)一下,那么你就必須給他們提供一下新版的cordova.js,進(jìn)入“www文件夾”,找找就會(huì)看到有三個(gè)js文件,不要想了,直接發(fā)給H5的同事,讓他們快點(diǎn)替換舊版cordova.js,修改一下處理邏輯,H5那邊處理起來(lái)很簡(jiǎn)單,別讓他們忽悠你說(shuō)搞不定或者需要幾天時(shí)間。
再假設(shè)H5那邊已經(jīng)把新版cordova集成完畢并且沒(méi)bug了,現(xiàn)在就到了iOS程序員裝逼的時(shí)候了,不多說(shuō),直接上干貨,一起看看cordova 4.4.0在架構(gòu)設(shè)計(jì)上,有哪些值得我們研究的地方:
首先看Cordova框架的整體類結(jié)構(gòu),類有很多,但是真正需要我們?nèi)リP(guān)心的沒(méi)幾個(gè),首先就是CDVViewController這個(gè)類,這個(gè)類和舊版的一樣,但是仔細(xì)看這個(gè)類就會(huì)發(fā)現(xiàn)它的屬性webView由UIWebView變成了UIView,這個(gè)和它需要支持WKWebView有關(guān),先說(shuō)說(shuō)思想(高手談思想,菜鳥談代碼,我們不做菜鳥),設(shè)計(jì)思想:
? ? ? ?通過(guò)一個(gè)協(xié)議CDVWebViewEngineProtocol來(lái)管理CDVUIWebViewEngineer和CDVWKWebViewEngineer,再通過(guò)CDVUIWebViewEngineer管理UIWebView,CDVWKWebViewEngineer管理WKWebView,說(shuō)到底,就是簡(jiǎn)單的面向協(xié)議編程,使用這個(gè)編程思想是必然的,因?yàn)閃KWebView和UIWebView有太多共性,只要抽象出共性,定義好協(xié)議接口,沒(méi)啥搞不定的。
再看看這個(gè)類的代碼,啥也不用想,直接來(lái)這個(gè)方法- (UIView*)newCordovaViewWithFrame:(CGRect)bounds,

仔細(xì)看會(huì)發(fā)現(xiàn),它是先從config.xml配置里面去取CordovaDefaultWebViewEngine這個(gè)key下的值CDVWKWebViewEngineer,如果配置里面設(shè)置了這個(gè)key值,就說(shuō)明需要使用CDVWKWebViewEngnieer,即使如此,它還要判斷一下是不是真的支持使用WK,這里提一個(gè)細(xì)節(jié):
WKWebView在iOS8.0時(shí)不能通過(guò)LoadRequest加載本地資源,這個(gè)bug已經(jīng)在iOS9.0解決了,可以看到上面已經(jīng)做了這個(gè)判斷是否繼續(xù)使用WKWebView。
這個(gè)類有一個(gè)屬性:

? ? ? ? ?解決方案:先不用知道wenViewEngineer到底是屬于CDVWKWebViewEngineer還是CDVUIWebViewEngnieer,但是我只知道它一定遵循CDVWebViewEngineProtocol這個(gè)協(xié)議,具體wenViewEngineer這個(gè)屬性是哪個(gè),是根據(jù)(UIView*)newCordovaViewWithFrame:(CGRect)bounds,這個(gè)方法系統(tǒng)自己推理出來(lái)的,所以我們拿到self.webEngineer后直接調(diào)用協(xié)議里面的方法,就可以加載網(wǎng)頁(yè)了,如果覺得方法不夠用,可以在CDVWebViewEngineProtocol協(xié)議里面添加,但添加的協(xié)議方法的實(shí)現(xiàn)必須在CDVWKWebViewEngineer和CDVUIWebViewEngnieer兩個(gè)類中都去實(shí)現(xiàn),不然必出問(wèn)題。
再看協(xié)議CDVWebViewEngineProtocol,協(xié)議里面有屬性engineWebView,其實(shí)就是當(dāng)前ViewController的webView(具體里面的屬性指針傳遞就不細(xì)說(shuō),就直接這么理解),協(xié)議方法用于給CDVWKWebViewEngineer和CDVUIWebViewEngnieer兩個(gè)類使用;
這樣,就簡(jiǎn)單但又直接的了解的cordova,其實(shí)知道了這些對(duì)于使用cordova做項(xiàng)目足矣。
最后,如何定義方法,如何定義JS插件呢?
很簡(jiǎn)單,在config.xml里面添加:

提供給H5同胞你的插件名和方法,讓H5那邊調(diào)一下,不出意外,Native這邊必然就可以響應(yīng)了,至于我的項(xiàng)目的整改,其實(shí)就包含WKWebView的使用和NSURLProtocol做離線緩存了,這里我先列舉一下遇到的坑:
1.WKWebView的Cookie不會(huì)從NSHTTPCookieStorage里面去取,但會(huì)往里面存,所以所有涉及到登錄的H5頁(yè)面沒(méi)法加載出來(lái),Cookie的解決方案接下來(lái)會(huì)說(shuō)明;
2.WKWebView使用NSURLProtocol做離線緩存時(shí),請(qǐng)求沒(méi)法攔截到,即使攔截到,請(qǐng)求體也被蘋果干掉了,如何解決,有幾個(gè)方案,接下來(lái)會(huì)說(shuō)明;
3.WKWebView有自己獨(dú)立的進(jìn)程,分配的資源很有限,開啟的WK多了,返回時(shí)會(huì)看看白屏,網(wǎng)上的解決方案貌似沒(méi)啥用,有一個(gè)解決方案,接下來(lái)會(huì)說(shuō)明;
4.WK自身設(shè)計(jì)上存在一些特殊的地方,接下來(lái)會(huì)分享出來(lái)。