簡單淺析 Cordova-iOS 核心代碼(iOS與JS互相調(diào)用)

本文可能只適合新手。基于Cordova 4.0+,講的比較膚淺,主要是記錄一下這段時(shí)間對Cordova的學(xué)習(xí)。文筆比較不好,如有錯(cuò)誤歡迎指正,歡迎探討。

總結(jié)在前:

OC調(diào)用js
一、webview 調(diào)用 stringByEvaluatingJavaScriptFromString 方法
注:同步方法,可能會阻塞UI
二、JavaScriptCore做js交互
JSContext *context = [self.webview valueForKeyPath:@“documentView.webView.mainFrame.javaScriptContext"]
[context evaluateScript:XXXX];

js調(diào)用OC
一、利用js打開iFrame方式發(fā)假請求,webview進(jìn)行攔截
(默認(rèn)方式)iframe的方法:添加iframe到html元素中,并設(shè)置iframe的src為指定gap://ready(相當(dāng)于發(fā)假的URL請求),觸發(fā)Native側(cè)UIWebview:shouldStartLoadWithRequest的方法。攔截住此次請求后再調(diào)用JS代碼向JS側(cè)發(fā)起取參數(shù)的操作,取回后Native再進(jìn)行處理。
注:為什么不用document.location: 如果我們連續(xù) 2 個(gè) js 調(diào) native,連續(xù) 2 次改 document.location 的話,在 native 的 delegate 方法中,只能截獲后面那次請求,前一次請求由于很快被替換掉,所以被忽略掉了
二、JavaScriptCore: 在webViewDidFinishLoad完成載入后,對上下文進(jìn)行設(shè)置
JSContext *context = [self.webView valueForKeyPath:”documentView.webView.mainFrame.javaScriptContext"]
context[@"share”] = ^(){….} //設(shè)置share 方法

一、簡單講下什么是Cordova

Apache Cordova是一個(gè)開源的移動開發(fā)框架。允許你用標(biāo)準(zhǔn)的web技術(shù)-HTML5,CSS3和JavaScript做跨平臺開發(fā)。 應(yīng)用在每個(gè)平臺的具體執(zhí)行被封裝了起來,并依靠符合標(biāo)準(zhǔn)的API綁定去訪問每個(gè)設(shè)備的功能,比如說:傳感器、數(shù)據(jù)、網(wǎng)絡(luò)狀態(tài)等。(摘自官網(wǎng))
同樣的移動開發(fā)框架,還有react-native, weex等等。這里不做比較和討論了。

二、講下這篇文章的背景

我們今天要講的,不是如何利用web技術(shù)去開發(fā)app。
而是底層最核心的代碼,native和js的交互。
現(xiàn)如今,Hybrid App非常盛行。我開發(fā)的工程也是Hybrid App。注重用戶體驗(yàn),且變動較少的頁面,使用Native開發(fā)。需要經(jīng)常迭代的,安卓iOS通用的頁面,就使用H5開發(fā)。而Native和H5的交互,我們使用的是Cordova工程的部分代碼,也就是比較核心的代碼,諸如CDVViewContoller等。

舉個(gè)例子:某公司的考勤頁面,是H5頁面。在自己公司的App打開這個(gè)頁面,如果要請假時(shí)需要填寫backup的同事,此時(shí)選擇同事是調(diào)用App Native本地存儲的通訊錄數(shù)據(jù)。這里就涉及到了JS與Native的相互調(diào)用和數(shù)據(jù)的傳遞。

三、整體的流程

1、利用CDVViewController(或是擴(kuò)展的類),去加載某個(gè)H5鏈接。
2、該H5頁面上某個(gè)按鈕的點(diǎn)擊事件需要請求Native插件。

(由于我們項(xiàng)目對CDVViewController又進(jìn)行了一層封裝,所以插件的加載,JS的注入,不需要對Cordova核心代碼進(jìn)行改動,如config.xml)

(--流程基本是通過斷點(diǎn)打出來看的--)


Cordova.png

四、具體是如何交互的,底層機(jī)制又是什么?

(JavaScriptCore也是交互的一種方式,但不在本章里討論 )

1、JS如何調(diào)用Native?

(默認(rèn)方式)iframe的方法:添加iframe到html元素中,并設(shè)置iframe的src為指定gap://ready(相當(dāng)于發(fā)假的URL請求),觸發(fā)Native側(cè)UIWebview:shouldStartLoadWithRequest的方法。攔截住此次請求后再調(diào)用JS代碼向JS側(cè)發(fā)起取參數(shù)的操作,取回后Native再進(jìn)行處理。

xmlHttpRequest的方法:
execXhr.open('HEAD', "/!gap_exec?" + (+new Date()), true);
   execXhr.setRequestHeader('cmds', iOSExec.nativeFetchMessages());
   Native側(cè)UIWebview:shouldStartLoadWithRequest的方法,判定為/!gap_exec來攔截,并從頭部取得插件的具體參數(shù)

保留該方式的原因:
// XHR mode does not work on iOS 4.2, so default to IFRAME_NAV for such devices.
// XHR mode’s main advantage is working around a bug in -webkit-scroll, which
// doesn’t exist in 4.X devices anyways
(iOS5.x版本因?yàn)?-webkit-scroll的IFRAME有BUG,則推薦使用)
因?yàn)槲覀冺?xiàng)目現(xiàn)在都是支持iOS 7+,所以采用的都是iframe方式。

2、Native如何執(zhí)行JS?

UIWebView 有一個(gè)這樣的方法 stringByEvaluatingJavaScriptFromString

3、底層機(jī)制是怎么樣的?

底層機(jī)制主要是結(jié)合1、2兩種方式,形成一種一來一往的交互(可以看上述流程圖)。
與普通調(diào)用1、2兩種方法相比較,最核心的點(diǎn)在于:
1、Cordova在JS側(cè)與Native側(cè)均使用了隊(duì)列來保存互相調(diào)用的請求,并生成了callbackid能及時(shí)找到與此次請求相關(guān)的上下文參數(shù)等等。
2、CDVPlugin、CommandDelegate等可以很好的開發(fā)插件。注入插件和js的話看個(gè)人,可以在繼承CDVViewController里面去做。

五、具體的插件開發(fā)是什么樣的

1、生成cfg文件(主要是對插件的描述)
2、生成.js文件(主要是供H5開發(fā)人員可以直接調(diào)用)
3、繼承CDVPlugin的類去寫插件類,有模板可仿照。
具體可看官網(wǎng) http://cordova.axuer.com/docs/zh-cn/latest/guide/platforms/ios/plugin.html

——————————————————————
參考文章:http://www.lxweimin.com/p/e74bc7abac8d (是講述js與OC調(diào)用的,一個(gè)系列的,還不錯(cuò))
http://blog.csdn.net/u011417590/article/details/50895734(是講述Cordova核心類CDVViewController源碼的)
http://blog.csdn.net/Linux7985/article/details/53022371 (相對清晰一點(diǎn),我的結(jié)構(gòu)也是模仿該篇的,可惜版本貌似比較老了)
http://blog.csdn.net/lq83623/article/details/42478223 (講的也比較好,但下面的結(jié)構(gòu)圖大部分看不懂)
http://www.lxweimin.com/p/21477a20707a (主要是插件開發(fā)相關(guān))

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。