隨着H5的強大,hybrid app已經成爲當前互聯網的大方向,單純的native app和web app在某些方面顯得就很劣勢。關於H5的發展史,這裏有一篇文章推薦給你們,今天咱們來學習最基礎的基於iOS系統的OC與JS之間是如何進行交互的,本文介紹的是基於UIWebView"協議攔截"實現的交互方式,固然後面還會按部就班的介紹其餘的交互方式。這裏的說到的JS指的是廣義上JS,並非單純的javascript,你能夠理解爲web前端的三件套(html+css+javascript);這裏說的OC指的是iOS的系統語言Objective-C,爲何叫作OC與JS交互而不是iOS與JS交互或者其餘名字,這個不是重點,也有叫web交互,H5交互的。本着儘量清楚解釋原理的目標,文章的組織形式採用圖文並茂加示例代碼javascript
先來一張圖,以下。簡要說明下:界面分爲兩部分,上半部分是UIWebView加載的本地html頁面,下半部分是原生UI繪製的界面。咱們這裏須要實現的功能是,分別點擊上面的(小黃)三個按鈕,會執行OC裏面對應的無參,1個參數,2個參數的方法;點擊下面的(小紅)三個按鈕,會執行HTML裏面對應的無參,1個參數,2個參數的JS方法。下面的介紹會結合這張圖,及相關代碼來詮釋如何用原生UIWebView攔截協議的方式實現JS交互的。本文的示例代碼會放在文章的後面,須要的同窗拿去不謝,能夠先下載示例DEMO查看效果css
OC與JS交互是雙向的,一方面是OC向JS發送消息,另外一方面是JS向OC發送消息。代碼上的表現形式就是方法的相互調用,分爲兩種:html
UIWebView內置一個方式能夠執行JavaScript代碼,所以OC調用JS比較方便點前端
- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
調用這個方法須要在網頁加載完成以後,由於這個時候整個html頁面包括js/css已經注入到webView中,此時調用方法纔會有響應,相反網頁加載完成以前調用界面不會有任何響應java
參考上圖,咱們點擊小紅部分的事件按鈕,會調用JS中的事件處理代碼git
OC部分:github
if (sender.tag == 123) { [self.webView stringByEvaluatingJavaScriptFromString:@"alertMobile()"]; } if (sender.tag == 234) { [self.webView stringByEvaluatingJavaScriptFromString:@"alertName('小紅')"]; } if (sender.tag == 345) { [self.webView stringByEvaluatingJavaScriptFromString:@"alertSendMsg('18870707070','週末登山真是件愉快的事情')"]; }
JS部分:web
function alertMobile() { alert('我是上面的小黃 手機號是:13300001111') } function alertName(msg) { alert('你好 ' + msg + ', 我也很高興見到你') } function alertSendMsg(num,msg) { alert('這是個人手機號:' + num + ',' + msg + '!!') }
UIWebView加載過程當中會有一系列代理方法,這裏不關注其餘的方法,只關注UIWebView在加載以前的一個代理方法數據結構
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
這是UIWebView在加載以前或者網頁進行重定向的時候調用的一個方法,而咱們JS調用OC採用協議攔截方式實現的細節就是在這個方法裏面完成的app
有了上面的方法後,很顯然,想要JS調用OC咱們就能夠採用在按鈕點擊的後重定向一個URL,這個URL攜帶OC的方法名及參數信息,而後在這個方法中拿到對應的URL,對URL進行解析,提取對應的方法名和參數信息,調用OC相應的方法,從而實現了交互的可能,下面是示例中的URL
rrcc://showSendNumber_msg_?13300001111&go climbing this weekend
在這個URL中前面的"rrcc://"是URL的scheme,經過這個來提取咱們關心的URL,對其餘URL不作任何處理,後面就是OC方法和參數的信息了,這裏用"?"來分割分割方法名和參數,"&"來分割多個參數,"_"用做OC方法名中冒號的替換。若是你願意,可使用任何幾個字符來定義這個規則,這裏採用的URL中常常會見到的字符。下面貼出部分示例代碼
JS部分:
function btnClick1() { location.href = "rrcc://showMobile" } function btnClick2() { location.href = "rrcc://showName_?xiaohuang" } function btnClick3() { location.href = "rrcc://showSendNumber_msg_?13300001111&go climbing this weekend" }
OC部分:
NSArray *components = [subPath componentsSeparatedByString:@"?"]; NSString *methodName = [components firstObject]; methodName = [methodName stringByReplacingOccurrencesOfString:@"_" withString:@":"]; SEL sel = NSSelectorFromString(methodName); NSString *parameter = [components lastObject]; NSArray *params = [parameter componentsSeparatedByString:@"&"]; if (params.count == 2) { if ([self respondsToSelector:sel]) { [self performSelector:sel withObject:[params firstObject] withObject:[params lastObject]]; } }
OC調用JS方法,若是有參數,直接在方面名後面的括號中寫入對應的參數便可;若是是含有多個參數,參數之間用","分開
JS調用OC方法,參數是攜帶在URL中,經過解析URL來調用對應的方法
下面咱們來分析下這種交互方式:
1. 因爲OC執行選擇器(selector)方法的限制,這種方式最多隻能傳遞參數的個數爲2個,若是須要多個參數,(開個腦洞)能夠從數據結構的組織方面入手
2. 每次須要發生交互的時候咱們都須要來自定義一個URL,而後解析URL,最後提取參數,合成方法名,找到對應的方法來調用;若是項目中有幾十上百個地方須要交互來完成,這樣一一來寫的話,顯然不是聰明的辦法,到時候你的代碼也會是雜亂,難以維護的,因此這種交互方式適用於項目中有少許,極個別的地方須要交互的需求。
3. 咱們嫌麻煩,前輩們確定也會嫌麻煩,有沒有解決辦法呢?iOS7以前,蘋果沒有出 JavaScriptCore 以前,業界廣泛採用開源庫WebViewJavascriptBridge和EasyJSWebView來解決的,原理都是基於攔截協議的封裝,採用率第一個要遠遠高於第二個,咱們將在下一篇文章中介紹WebViewJavascriptBridge的具體使用方法
戳這裏:本文的DEMO地址歡迎star