OC與JS代碼交互原理(混合開發(fā)讯柔,包含UIWebView、WKWebView)

簡(jiǎn)單說兩句护昧,混合開發(fā)的App(Hybrid App)就是在一個(gè)App中內(nèi)嵌一個(gè)輕量級(jí)的瀏覽器魂迄,一部分原生的功能改為Html 5來開發(fā),這部分功能不僅能夠在不升級(jí)App的情況下動(dòng)態(tài)更新惋耙,而且可以在Android或iOS的App上同時(shí)運(yùn)行捣炬,讓用戶的體驗(yàn)更好又可以節(jié)省開發(fā)的資源。
混合開發(fā)又它的優(yōu)勢(shì)绽榛,也有其劣勢(shì)湿酸。所以并不是所有的app都適合混合開發(fā),對(duì)于一些強(qiáng)交互的app用h5來做的話灭美,會(huì)事倍功半推溃,而且體驗(yàn)上面也會(huì)大打折扣。所以届腐,公司在選擇開發(fā)模式的時(shí)候铁坎,一定要選擇適合自己產(chǎn)品的,而不是一味的跟風(fēng)

關(guān)于第三發(fā)框架有很多犁苏,這里就不一一列舉(我知道的也不多)硬萍,在這里我介紹一下交互的底層原理,對(duì)于iOS主要分為(UIWebView-JS围详、WKWebView-JS)朴乖,兩者的原理有所不同,但是都需要了解的

UIWebView 與JS交互

OC調(diào)用JS

這里蘋果公司已經(jīng)為我們封裝好了一個(gè)方法
其中script里面放的就是純JS代碼短曾,而我們只需要用UIWebView的

stringByEvaluatingJavaScriptFromString:(NSString *)script

對(duì)象方法就可以直接執(zhí)行字符串所存儲(chǔ)的JS代碼寒砖,當(dāng)然,這個(gè)執(zhí)行嫉拐,是在整個(gè)頁(yè)面加載完以后才會(huì)去執(zhí)行的哩都。

NSString *js = @"var div = document.getElementById('div1'); div.style.backgroundColor = 'yellow';div.addEventListener('click',divClick);function divClick(){alert('123456789')}";
    /*加載js腳本*/
 [_webView stringByEvaluatingJavaScriptFromString:js];

JS調(diào)用OC

這需要UIWebView的一個(gè)代理方法來輔助操作,當(dāng)JS需要調(diào)用OC 的一個(gè)方法的時(shí)候會(huì)主動(dòng)發(fā)起一個(gè)網(wǎng)絡(luò)請(qǐng)求

window.location.href = "openimagepicker://"

只要JS掉用和href這個(gè)方法婉徘,就會(huì)走UIWebView 的代理方法:

(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType

并且將 "openimagepicker://"當(dāng)做request 傳進(jìn)來漠嵌,也就是說咐汞,我們需要在這個(gè)代理方法里來攔截這個(gè)request,看是否是OC來處理的儒鹿,比如說我當(dāng)前發(fā)送的request的意思是"打開相冊(cè)"(事先約定好)化撕,我通過webview 的代理方法攔截到了這個(gè)請(qǐng)求,那么我就會(huì)主動(dòng)的掉起系統(tǒng)原生相冊(cè)约炎,代碼如下:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSLog(@"%@",request.URL.absoluteString);
    //獲取webView發(fā)送的請(qǐng)求
    NSString *urlString = request.URL.absoluteString;
    /**
     *  打開相冊(cè)
     */
    if ([urlString isEqualToString:@"openimagepicker://"])
    {
        [self openImagePicker];
        return NO;
    }
    return YES;
}
- (void)openImagePicker
{
    UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
    [self presentViewController:imagePickerController animated:YES completion:nil];
}

return NO是為了不讓webview 來處理這次網(wǎng)絡(luò)請(qǐng)求植阴,因?yàn)檫@并不是一次真正的網(wǎng)絡(luò)請(qǐng)求

WKWebView與JS交互

JS調(diào)用OC

相對(duì)于UIWebView,WKWebView與JS進(jìn)行交互時(shí)則要麻煩很多圾浅,大體上分為3個(gè)步驟:
1.首先我們?cè)诔跏蓟疻KWebView的時(shí)候 需要將一個(gè)配置項(xiàng)同事給webView掠手,這里面的配置項(xiàng),使我們來注冊(cè)handler的(一會(huì)再解釋這是干啥的)
2.注冊(cè)完后狸捕,網(wǎng)頁(yè)跑了起來喷鸽,JS需要通過window.webkit.messageHandlers.<name>.postMessage(<messageBody>)調(diào)用的觸發(fā)webView的代理方法
3.Native(原生)通過代理方法,來處理響應(yīng)的事件

需要的類(OC)

WKWebViewConfiguration 這個(gè)類就是webView初始化時(shí)候的配置項(xiàng)灸拍,它會(huì)有一個(gè)方法做祝,讓我們來注冊(cè)handler

- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;

這個(gè)方法就是來注冊(cè)handler用的

完整代碼塊

NSString *path = [[NSBundle mainBundle] pathForResource:@"index.html" ofType:nil];
    //2.讀取文件中的內(nèi)容
NSString *string = [NSString stringWithContentsOfURL:[NSURL fileURLWithPath:path] encoding:NSUTF8StringEncoding error:nil];
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
    //注冊(cè),方便js調(diào)用oc代碼
[configuration.userContentController addScriptMessageHandler:self name:@"OpenImagePicker"];
[configuration.userContentController addScriptMessageHandler:self name:@"SystemVersion"];
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];
    //加載指定的HTML字符串
[webView loadHTMLString:string baseURL:nil];
webView.UIDelegate = self;
[self.view addSubview:webView];

假如JS主動(dòng)調(diào)起了OC鸡岗,webView 的這個(gè)代理方法會(huì)立即執(zhí)行,我們可以在這里處理JS需要Native做的事情

//JS通過window.webkit.messageHandlers.<name>.postMessage(<messageBody>)調(diào)用的觸發(fā)此代理方法
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    //打開相冊(cè)
    if ([message.name isEqualToString:@"OpenImagePicker"])
    {
        //js的傳過來的數(shù)據(jù)
        NSLog(@"%@",message.body);
        UIImagePickerController *picker = [[UIImagePickerController alloc] init];
        [self presentViewController:picker animated:YES completion:nil];
        
    }
    //獲取系統(tǒng)版本
    if ([message.name isEqualToString:@"SystemVersion"])
    {...}
}

那么問題來了混槐?JS怎么來主動(dòng)掉起Native 來這行上面這個(gè)代理方法呢,還記得剛才注冊(cè)的handler么纤房?那是注冊(cè)在webView上的纵隔,就相當(dāng)于OC跟JS事先商量好,有哪些字段會(huì)調(diào)起我的代理方法炮姨,其他字段是不可以的捌刮!
JS 的代碼如下:

window.webkit.messageHandlers.OpenImagePicker.postMessage("123456789")

其中,"OpenImagePicker"并不是JS 的方法名舒岸,而是我們之前在webView里注冊(cè) 的handler绅作,"postMessage"是JS帶給OC 的一些信息,如果"OpenImagePicker"我們事先沒有注冊(cè)到webView里蛾派,當(dāng)JS執(zhí)行這句代碼時(shí)俄认,是不會(huì)走webView 的代理方法的。

OC調(diào)用JS

OC調(diào)用JS相對(duì)要簡(jiǎn)單一些洪乍,有兩種眯杏,其中一種跟UIWebView 的方法一樣,都是系統(tǒng)自帶的方法壳澳,下面貼代碼

[webView evaluateJavaScript:@"function sum(a,b){return a + b};sum(1,2)" completionHandler:^(id result, NSError * _Nullable error) {
        NSLog(@"%@",result);
    }];

自己去看log出來的結(jié)果是啥

還有第二種岂贩,就是在webView初始化的時(shí)候,直接注入JS代碼巷波,放在JS代碼的最后面執(zhí)行萎津,貼代碼

 //初始化了script
    WKUserScript *script = [[WKUserScript alloc] initWithSource:@"buttonClick()" injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
    //執(zhí)行js語(yǔ)言的
    [configuration.userContentController addUserScript:script];
    
    WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];
    //加載指定的HTML字符串
    [webView loadHTMLString:string baseURL:nil];
    webView.UIDelegate = self;
    //加載指定路徑下的文件
    [self.view addSubview:webView];

多余的代碼我沒貼卸伞,這里還是很容易懂的。

總結(jié):?jiǎn)魡暨@么多锉屈,就是讓大家知道荤傲,我是誰?我在哪颈渊?在干嗎遂黍?原理還是要略知一二的,大多數(shù)用的都是別人的框架俊嗽,用的時(shí)候很少考慮原理妓湘,當(dāng)業(yè)務(wù)需求有變化的時(shí)候,需要改底層框架乌询!就會(huì)感嘆一句:臥槽!我是誰豌研?我在哪妹田?在干嗎?

                                                                                                     阿里嘎豆鹃共!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鬼佣,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子霜浴,更是在濱河造成了極大的恐慌晶衷,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件阴孟,死亡現(xiàn)場(chǎng)離奇詭異晌纫,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)永丝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門锹漱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人慕嚷,你說我怎么就攤上這事哥牍。” “怎么了喝检?”我有些...
    開封第一講書人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵嗅辣,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我挠说,道長(zhǎng)澡谭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任纺涤,我火速辦了婚禮译暂,結(jié)果婚禮上抠忘,老公的妹妹穿的比我還像新娘。我一直安慰自己外永,他們只是感情好崎脉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著伯顶,像睡著了一般囚灼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上祭衩,一...
    開封第一講書人閱讀 51,258評(píng)論 1 300
  • 那天灶体,我揣著相機(jī)與錄音,去河邊找鬼掐暮。 笑死蝎抽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的路克。 我是一名探鬼主播樟结,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼精算!你這毒婦竟也來了瓢宦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤灰羽,失蹤者是張志新(化名)和其女友劉穎驮履,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體廉嚼,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡玫镐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了前鹅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摘悴。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖舰绘,靈堂內(nèi)的尸體忽然破棺而出蹂喻,到底是詐尸還是另有隱情,我是刑警寧澤捂寿,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布口四,位于F島的核電站,受9級(jí)特大地震影響秦陋,放射性物質(zhì)發(fā)生泄漏蔓彩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望赤嚼。 院中可真熱鬧旷赖,春花似錦、人聲如沸更卒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蹂空。三九已至俯萌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間上枕,已是汗流浹背咐熙。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留辨萍,地道東北人棋恼。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像锈玉,于是被迫代替她去往敵國(guó)和親蘸泻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容