UIWebView 與 JS 交互(1): stringByEvaluatingJavaScriptFromString方法的調用

 本文非原創,由於無法直接轉載到此,所以直接粘過來收藏。

原文鏈接:http://blog.oneapm.com/apm-tech/534.html

作爲一名普通的iOS開發者,我們在項目中也會或多或少的用到一些JS代碼,如何實現JS和OC之間的交互常常是我們會面臨的一個問題。最近一段時間,由於工作需要,研究了iOS下與JS交互的問題.

第一個要說的就是如何在OC下調用JS,這個很簡單,想必大家都會不約而同的回答出,使用UIWebView的stringByEvaluatingJavaScriptFromString方法。

接下來我從自己的實際經歷聊一下如何使用stringByEvaluatingJavaScriptFromString調用javascript

1、 stringByEvaluatingJavaScriptFromString只能在主線程執行。

比如,假如你調用了下面這段代碼:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  
dispatch_async(queue, ^{  
    [webView stringByEvaluatingJavaScriptFromString:@"aaa"];
});

程序就會崩潰,並打出下面的log:

崩潰產生的原因是你在主線程以外的線程調用了UIKit,系統在執行stringByEvaluatingJavaScriptFromString的時候調用了UIKit裏的一些方法,所以不允許在主線程之外的線程去調用這個方法。

解決方法也有很多可以用

[webView performSelectorOnMainThread:]

或者

dispatch_sync(dispatch_get_main_queue(), ^{  
    [webView stringByEvaluatingJavaScriptFromString:@"aaa"];
});        

2、簡單調用系統提供的javascript方法

對於一些簡單的javascript系統方法,我們可以通過 stringByEvaluatingJavaScriptFromString 做一下簡單的調用,並取得返回值。 

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    NSString *title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
    NSLog(@"%@", title);
}

3、在加載的html裏插入代碼,並執行

比如我用下面的代碼插入了一個名叫alertTest的函數到javascript裏實現在頁面中顯示alert的功能。

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
        [webView stringByEvaluatingJavaScriptFromString:
         @"var script = document.createElement('script');"
         "script.type = 'text/javascript';"
         "script.text = \"function alertTest(str) { "
         "alert(str)"
         "}\";"
         "document.getElementsByTagName('head')[0].appendChild(script);"];
         [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"alertTest('%@');", @"test"]];
}

值得注意的一點是 - (void)webViewDidFinishLoad:(UIWebView *)webView 方法指的並不是webview完全加載完畢,而是指網頁中一個iframe或frame加載完畢,也就是說假如網頁裏有多個frame,那麼 webViewDidFinishLoad 會執行多次。這就會導致上面插入代碼的方法會執行多次, stringByEvaluatingJavaScriptFromString 執行JS是一筆不小的時間開銷,所以我們應該儘量減少使用它去執行復雜的JS代碼。 

我使用了下面的方式檢查是否已經插入並執行了這個函數,typeof alertTest檢查了alertTest這個函數是否存在,若存在則不執行if裏面的代碼插入和代碼執行語句。

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    BOOL isExist = [[webView stringByEvaluatingJavaScriptFromString:@"typeof alertTest == \'function\';"] isEqualToString:@"true"];
    if (!isExist) {
        [webView stringByEvaluatingJavaScriptFromString:
         @"var script = document.createElement('script');"
         "script.type = 'text/javascript';"
         "script.text = \"function alertTest(str) { "
         "alert(str)"
         "}\";"
         "document.getElementsByTagName('head')[0].appendChild(script);"];
        [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"alertTest('%@');", @"test"]];
    }
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章