JS與OC交互/方法的相互調(diào)用

iOS下JS與原生OC互相調(diào)用(總結(jié))

iOS開發(fā)免不了要與UIWebView打交道鹃共,然后就要涉及到JS與原生OC交互供汛,今天總結(jié)一下JS與原生OC交互的兩種方式岖常。JS調(diào)用原生OC篇方式一第一種方式是用JS發(fā)起一個(gè)假的URL請(qǐng)求钞脂,然后利用UIWebView的代理方法攔截這次請(qǐng)求纵散,然后再做相應(yīng)的處理。我寫了一個(gè)簡單的HTML網(wǎng)頁和一個(gè)btn點(diǎn)擊事件用來與原生OC交互人芽,HTML代碼如下:

function showAlert(message){

        alert(message);

}

function loadURL(url) {

    var iFrame;

    iFrame = document.createElement("iframe");

    iFrame.setAttribute("src", url);

    iFrame.setAttribute("style", "display:none;");

    iFrame.setAttribute("height", "0px");

    iFrame.setAttribute("width", "0px");

    iFrame.setAttribute("frameborder", "0");

    document.body.appendChild(iFrame);

    // 發(fā)起請(qǐng)求后這個(gè) iFrame 就沒用了望几,所以把它從 dom 上移除掉

    iFrame.parentNode.removeChild(iFrame);

    iFrame = null;

}

function firstClick() {

         loadURL("firstClick://shareClick?title=分享的標(biāo)題&content=分享的內(nèi)容&url=鏈接地址&imagePath=圖片地址");

}

這里是第一種方式

Click Me!然后在項(xiàng)目的控制器中實(shí)現(xiàn)UIWebView的代理方法:

#pragma mark - UIWebViewDelegate
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{   

   NSURL * url = [request URL]; 
   if ([[url scheme] isEqualToString:@"firstclick"]) {       
         NSArray *params =[url.query componentsSeparatedByString:@"&"];       
         NSMutableDictionary *tempDic = [NSMutableDictionary dictionary];       
         for (NSString *paramStr in params) {           
                 NSArray *dicArray = [paramStr componentsSeparatedByString:@"="];            
                if (dicArray.count > 1) {               
                 NSString *decodeValue = [dicArray[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];               
                 [tempDic setObject:decodeValue forKey:dicArray[0]];           
         }       
       }     
       UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"方式一" message:@"這是OC原生的彈出窗" delegate:self cancelButtonTitle:@"收到" otherButtonTitles:nil];     
               [alertView show];      
                NSLog(@"tempDic:%@",tempDic);       
                 return NO;    
        }    
        return YES;
}

注意:

  1. JS中的firstClick,在攔截到的url scheme全都被轉(zhuǎn)化為小寫。
    2.html中需要設(shè)置編碼萤厅,否則中文參數(shù)可能會(huì)出現(xiàn)編碼問題橄抹。
    3.JS用打開一個(gè)iFrame的方式替代直接用document.location的方式靴迫,以避免多次請(qǐng)求,被替換覆蓋的問題楼誓。

早期的JS與原生交互的開源庫很多都是用得這種方式來實(shí)現(xiàn)的玉锌,例如:PhoneGap、WebViewJavascriptBridge疟羹。
關(guān)于這種方式調(diào)用OC方法主守,唐巧早期有篇文章有過介紹:
關(guān)于UIWebView和PhoneGap的總結(jié)方式二在iOS 7之后,apple添加了一個(gè)新的庫JavaScriptCore阁猜,用來做JS交互丸逸,因此JS與原生OC交互也變得簡單了許多。
首先導(dǎo)入JavaScriptCore庫, 然后在OC中獲取JS的上下文

JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

再然后定義好JS需要調(diào)用的方法剃袍,例如JS要調(diào)用share方法:
則可以在UIWebView加載url完成后,在其代理方法中添加要調(diào)用的share方法:

- (void)webViewDidFinishLoad:(UIWebView *)webView{    
        JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];    
        //定義好JS要調(diào)用的方法, share就是調(diào)用的share方法名    
        context[@"share"] = ^() {       
                NSLog(@"+++++++Begin Log+++++++");       
                NSArray *args = [JSContext currentArguments];        
                dispatch_async(dispatch_get_main_queue(), ^{            
                        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"方式二" message:@"這是OC原生的彈出窗" delegate:self cancelButtonTitle:@"收到" otherButtonTitles:nil];            
                        [alertView show];       
                 });       
                for (JSValue *jsVal in args) {            
                        NSLog(@"%@", jsVal.toString);        
                }        
              NSLog(@"-------End Log-------");    
        };
}

注意:可能最新版本的iOS系統(tǒng)做了改動(dòng)捎谨,現(xiàn)在(iOS9民效,Xcode 7.3,去年使用Xcode 6 和iOS 8沒有線程問題)中測(cè)試,block中是在子線程涛救,因此執(zhí)行UI操作畏邢,控制臺(tái)有警告,需要回到主線程再操作UI检吆。
其中相對(duì)應(yīng)的html部分如下:

function secondClick() {

share('分享的標(biāo)題','分享的內(nèi)容','圖片地址');

}

function showAlert(message){

alert(message);

}

這里是第二種方式

Click Me!JS部分確實(shí)要簡單的多了舒萎。
OC調(diào)用JS篇方式一

NSString *jsStr = [NSString stringWithFormat:@"showAlert('%@')",@"這里是JS中alert彈出的message"];
[_webView stringByEvaluatingJavaScriptFromString:jsStr];

注意:該方法會(huì)同步返回一個(gè)字符串,因此是一個(gè)同步方法蹭沛,可能會(huì)阻塞UI臂寝。方式二繼續(xù)使用JavaScriptCore庫來做JS交互。

JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
NSString *textJS = @"showAlert('這里是JS中alert彈出的message')";
[context evaluateScript:textJS];

重點(diǎn):
stringByEvaluatingJavaScriptFromString是一個(gè)同步的方法摊灭,使用它執(zhí)行JS方法時(shí)咆贬,如果JS 方法比較耗的時(shí)候,會(huì)造成界面卡頓帚呼。
尤其是js 彈出alert 的時(shí)候掏缎。
alert 也會(huì)阻塞界面,等待用戶響應(yīng)煤杀,而stringByEvaluatingJavaScriptFromString又會(huì)等待js執(zhí)行完畢返回眷蜈。這就造成了死鎖。
官方推薦使用WKWebView的evaluateJavaScript:completionHandler:代替這個(gè)方法沈自。
其實(shí)我們也有另外一種方式酌儒,自定義一個(gè)延遲執(zhí)行alert 的方法來防止阻塞,然后我們調(diào)用自定義的alert 方法酥泛。
同理今豆,耗時(shí)較長的js 方法也可以放到setTimeout 中嫌拣。

function asyncAlert(content) {    
        setTimeout(function(){        
                alert(content);        
        },1);
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市呆躲,隨后出現(xiàn)的幾起案子异逐,更是在濱河造成了極大的恐慌,老刑警劉巖插掂,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件灰瞻,死亡現(xiàn)場離奇詭異,居然都是意外死亡辅甥,警方通過查閱死者的電腦和手機(jī)酝润,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來璃弄,“玉大人要销,你說我怎么就攤上這事∠目椋” “怎么了疏咐?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長脐供。 經(jīng)常有香客問我浑塞,道長,這世上最難降的妖魔是什么政己? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任酌壕,我火速辦了婚禮,結(jié)果婚禮上歇由,老公的妹妹穿的比我還像新娘卵牍。我一直安慰自己,他們只是感情好印蓖,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布辽慕。 她就那樣靜靜地躺著,像睡著了一般赦肃。 火紅的嫁衣襯著肌膚如雪溅蛉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天他宛,我揣著相機(jī)與錄音船侧,去河邊找鬼。 笑死厅各,一個(gè)胖子當(dāng)著我的面吹牛镜撩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播队塘,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼袁梗,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼宜鸯!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起遮怜,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤淋袖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后锯梁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體即碗,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年陌凳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了剥懒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡合敦,死狀恐怖初橘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蛤肌,我是刑警寧澤壁却,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站裸准,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏赔硫。R本人自食惡果不足惜炒俱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望爪膊。 院中可真熱鬧权悟,春花似錦、人聲如沸推盛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽耘成。三九已至榔昔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間瘪菌,已是汗流浹背撒会。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留师妙,地道東北人诵肛。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像默穴,于是被迫代替她去往敵國和親怔檩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子褪秀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

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