iOS JS 和 OC互動 / JS 和 native 相互調用

來源:互聯網
上載者:User

標籤:閉包   sde   名稱   nim   成功   life   strong   rip   本地   

現在app 上越來越多需求是通過UIWebView 來展示html 或者 html5的內容, js 和 native OC代碼互動 就非常常見了.

js 調用 native  OC代碼

第一種機制

(1)最常用的是 利用 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType 這個UIWebView 代理方法裡攔截 JS 發送的請求,如果是約定的請求 那麼就觸發本地該執行的OC方法

我遇到常用的兩種情境:

(1.1)頁面緩衝載入過程中 該shouldStartLoadWithRequest:就可攔截多個請求,尋找約定的關鍵字,鎖定約定請求即可觸發本地OC

(1.2)頁面有按鈕類別的焦點地區, 點擊觸發請求,通過 shouldStartLoadWithRequest: 對請求進行判斷 ,觸發本地OC

     舉例:html 分享按鈕

<html>    <header>        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />        <script type="text/javascript">function shareClick() {                loadURL("iOS//:shareAction");//這個連結對應 下面iOS方法中同一連結的關鍵字            }        </script>    </header>    <body>        <h2> 點擊webView上面的按鈕 觸發本地 OC 分享方法 </h2>        <button type="button" onclick="shareClick()">按鈕名稱</button>    </body></html>

 

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{    NSString *requestUrl = request.URL.absoluteString;
DLog(@"請求URL:%@",requestUrl);
//判斷是商品 if(![NSString isEmpty:requestUrl] && [requestUrl hasPrefix:@"hfmall://"]) {//約定 按請求首碼 是"hfmall://"來判斷是商品 甚至可以從請求連結裡面截取有效參數 如果頻繁處理並且幾個參數或者說有特殊字元,應該考慮用json進行64位編拼在連結上傳過來 NSRange range = [requestUrl rangeOfString:@"hfmall://"]; if (range.length > 0) { NSString *shangpinId = [requestUrl substringFromIndex:range.length]; GoodsDetailViewController *detailVC = [[GoodsDetailViewController alloc] init]; detailVC.shangpin_id = shangpinId; [self.navigationController pushViewController:detailVC animated:YES]; return NO; //執行本地代碼 返回NO } }
//點擊UIWebView頁面上分享按鈕 執行本地OC 分享方法
//是文章分享
   NSRange range1 = [requestUrl rangeOfString:@"ios//:shareAction"];
if (range1.length != 0) {
[self share]; //執行分享方法
return NO;
}
//TODO:其他情況攔截判斷
return YES;//無有效需要攔截的連結 走系統預設方法
}

 

第二種機制

JavaScripCore

該架構 在 iOS7開始出現,可以實現 js 和 native OC原生互動,添加標頭檔#import <JavaScriptCore/JavaScriptCore.h>

 

[webView loadRequest:request];請求開始或者請求完成後擷取js上下文

(1)js 自由選擇時機調用native端 OC 代碼

html端

<html>    <header>        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />        <script type="text/javascript">            function secondClick() {                iosHideBottomBar(‘參數1‘,‘參數2‘);//和 OC代碼中標記紅色背景關鍵名稱一樣 即可識別            }
</script> </header> <body> <h2> js 自由選擇時機調用native端 OC 代碼 </h2> <button type="button" onclick="secondClick()">按鈕名稱</button> </body></html>

 

//擷取js上下文
JSContext
*context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

  context[@"iosHideBottomBar"] = ^() { // @"iosHideBottomBar"為和js 約定執行的方法名,這樣js 可以自由選擇時機調用native端 OC 代碼

        DLog(@"%@",[NSThread currentThread]);//列印當前線程

     NSArray *args = [JSContext currentArguments];//回調js 方法iosHideBottomBar傳遞的參數

        for (JSValue *jsVal in args) {

            DLog(@"%@", jsVal.toString);

        }

        __block JSContext *contextObject = context;

       dispatch_async(dispatch_get_main_queue(), ^{

            self.isShowLikeFooter = NO;

            [self handleHiddenBottomBar];

            NSString *[email protected]"xxxxx(‘如果需要傳遞傳回值‘)"; //準備執行的js代碼 按約定方法xxxxx回傳傳回值

            [contextObject evaluateScript:jsString];

        });

  };

 //該閉包是在非主線程中得到的回調,如果需要處理UI要在主線程更新 當前測試環境 為 XCode 8.0 模擬器 5s 8.3 列印結果如下

/**
2016-11-11 17:05:54.447 dailylife[4163:181210] <NSThread: 0x7ff68cc2fd90>{number = 7, name = (null)}

(lldb) po [NSThread currentThread]

<NSThread: 0x7ff68a423150>{number = 1, name = main}

**/

 小節:

兩種機制不同:

a.  前者需要 不斷對js 發起的每一條請求進行過濾判斷,再執行早已定義好的OC方法,因為無法預知具體需要觸發本地OC方法時機,

b.  後者 js 和 OC約定同一個方法名做識別關鍵字iosHideBottomBar 年 在JSContext擷取webView js上下文,告訴js 本地有這個同樣方法名的OC方法,你可以隨時調用(子線程中).

體驗下來,發現 後者這種 webView 控制調用更合理,在需要的時候調用.  但是現在好多第三方 用的都是前者,攔截url判斷的方法,比如"有贊"就是,所以兩種方法 我們都應該掌握,在需要的的時候選擇相對更優的方式處理實現

native OC 調用 js

調用時機是應該是 webFinishLoad後, 

(1)stringByEvaluatingJavaScriptFromString : 我常用這個方法去擷取 webView標題

NSString *title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];

@"document.title" 傳遞給js  (js call native) 是非同步

當js 返回的 title字串 (native call  js) 是同步得到的

stringByEvaluatingJavaScriptFromString 方法應該在主線程中執行,

這個方法也可以oc js相互傳遞參數 

這個方法調用時機:應該在webview 請求完成後再調用 js 方法,這裡才能用stringByEvaluatingJavaScriptFromString,因為

要等頁面載入完,頁面沒載入完就相當於有些對象不一定建立成功,那麼用js時候就容易找不到對象

(2)

//建立對象 context 擷取 js上下文JSContext *context=[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];      \
NSString *jsString=@"iosHideBottomBar(‘參數1‘,‘參數2‘)"; //準備執行的js代碼 並向iOS 傳遞參數1 參數2[context evaluateScript:jsString];//通過oc方法調用js的 iosHideBottomBar

 

其他情況:

我還特意考慮了 相互需要傳回值的可能

在具體上面方法舉例,使用方法名時候 有特意強調參數,和傳回值的情況不再贅述

參考:

http://blog.devtang.com/2012/03/24/talk-about-uiwebview-and-phonegap/

http://www.jianshu.com/p/d19689e0ed83

 

iOS JS 和 OC互動 / JS 和 native 相互調用

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.