Objective-C與javascript交互

Objective-C調(diào)用javascript
一.stringByEvaluatingJavaScriptFromString 方法可以將javascript嵌入頁(yè)面中柴罐,通過(guò)這個(gè)方法我們可以在iOS中與UIWebView中的網(wǎng)頁(yè)元素交互蜒秤,需要等UIWebView中的頁(yè)面加載完成之后去調(diào)用。

//插入js 并且執(zhí)行傳值
-(IBAction)insertJSTouched:(id)sender {
    NSString *insertString = [NSString stringWithFormat:
                              @"var script = document.createElement('script');"
                              "script.type = 'text/javascript';"
                              "script.text = \"function jsFunc() { "
                              "var a=document.getElementsByTagName('body')[0];"
                              "alert('%@');"
                              "}\";"
                              "document.getElementsByTagName('head')[0].appendChild(script);", self.someString];
    NSLog(@"insert string %@",insertString);
    [self.myWeb stringByEvaluatingJavaScriptFromString:insertString];
    [self.myWeb stringByEvaluatingJavaScriptFromString:@"jsFunc();"];
}
//提交form表單
- (IBAction)submitTouched:(id)sender {
    [self.myWeb stringByEvaluatingJavaScriptFromString:@"document.forms[0].submit(); "];
}
//修改標(biāo)簽屬性
- (IBAction)fontTouched:(id)sender {
    NSString *tempString2 = [NSString stringWithFormat:@"document.getElementsByTagName('p')[0].style.fontSize='%@';",@"19px"];
    [self.myWeb stringByEvaluatingJavaScriptFromString:tempString2];
}

二.JavaScriptCore&& UIWebview >=iOS7
iOS7中加入了JavaScriptCore.framework框架蔚润。把 WebKit 的 JavaScript 引擎用 Objective-C 封裝。該框架讓Objective-C和JavaScript代碼直接的交互變得更加的簡(jiǎn)單方便。
合適時(shí)機(jī)注入交互對(duì)象
什么時(shí)候UIWebView會(huì)創(chuàng)建JSContext環(huán)境?
分兩種方式
第一在渲染網(wǎng)頁(yè)時(shí)遇到<script標(biāo)簽時(shí)璃吧,就會(huì)創(chuàng)建JSContext環(huán)境去運(yùn)行JavaScript代碼。
第二就是使用方法
[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]去獲取JSContext環(huán)境時(shí)废境,這時(shí)無(wú)論是否遇到<script標(biāo)簽畜挨,都會(huì)去創(chuàng)造出來(lái)一個(gè)JSContext環(huán)境,而且和遇到<script標(biāo)簽再創(chuàng)造環(huán)境是同一個(gè)噩凹。
什么時(shí)候注入JSContext問(wèn)題
我通常都會(huì)在 - (void)webViewDidFinishLoad:(UIWebView *)webView中去注入交互對(duì)象巴元,但是這時(shí)候網(wǎng)頁(yè)還沒(méi)加載完,JavaScript那邊已經(jīng)調(diào)用交互方法驮宴,這樣就會(huì)調(diào)不到原生應(yīng)用的方法而出現(xiàn)問(wèn)題逮刨。
改成在- (void)viewDidLoad中去注入交互對(duì)象,這樣倒是解決了上面的問(wèn)題,但是同時(shí)又引起了一個(gè)新的問(wèn)題就是在一個(gè)網(wǎng)頁(yè)內(nèi)部點(diǎn)擊鏈接跳轉(zhuǎn)到另一個(gè)網(wǎng)頁(yè)的時(shí)候修己,第二個(gè)頁(yè)面需要交互恢总,這時(shí)JSContext環(huán)境已經(jīng)變化,但是- (void)viewDidLoad僅僅加載一次睬愤,跳轉(zhuǎn)的時(shí)候片仿,沒(méi)有再次注入交互對(duì)象,這樣就會(huì)導(dǎo)致第二個(gè)頁(yè)面沒(méi)法進(jìn)行交互尤辱。當(dāng)然你可以在- (void)viewDidLoad和- (void)webViewDidFinishLoad:(UIWebView *)webView都注入一次砂豌,但是一定會(huì)有更優(yōu)雅的辦法去解決此問(wèn)題。
如果上邊的方案能滿足需求,建議實(shí)在迫不得已再用這個(gè)方法, 就是在每次創(chuàng)建JSContext環(huán)境的時(shí)候光督,我們都去注入此交互對(duì)象這樣就解決了上面的問(wèn)題阳距。具體解決辦法參考了此開(kāi)源庫(kù)UIWebView-TS_JavaScriptContext
多個(gè)iFrame中的JSContext問(wèn)題

NSArray *frames = [webView valueForKeyPath:@"documentView.webView.mainFrame.childFrames"];
[frames enumerateObjectsUsingBlock:^(id frame, NSUInteger idx, BOOL *stop) {
    JSContext *context = [frame valueForKeyPath:@"javaScriptContext"];
    context[@"Window"][@"prototype"][@"alert"] = ^(NSString *message) {
            NSLog(@"%@", message);
    };
}];

1.JavaScriptCore調(diào)用Objective-C UIWebview的delegate

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    // 以 html title 設(shè)置 導(dǎo)航欄 title
    self.title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
    // Undocumented access to UIWebView's JSContext
    self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    // 打印異常
    self.context.exceptionHandler =
    ^(JSContext *context, JSValue *exceptionValue)
    {
        context.exception = exceptionValue;
        NSLog(@"%@", exceptionValue);
    };
    
    // 以 JSExport 協(xié)議關(guān)聯(lián) native 的方法
    self.context[@"app"] = self;
    
    // 以 block 形式關(guān)聯(lián) JavaScript function
    self.context[@"log"] =
    ^(NSString *str)
    {
        NSLog(@"%@", str);
    };
    //多參數(shù)
    self.context[@"mutiParams"] =
    ^(NSString *a,NSString *b,NSString *c)
    {
        NSLog(@"%@ %@ %@",a,b,c);
    };
    
}

2.Objective-C 調(diào)用 JavaScriptCore
Objective-C

調(diào)用js的showResult方法结借,這里是一個(gè)參數(shù) result筐摘,多個(gè)就依次寫(xiě)到數(shù)組中

[self.context[@"showResult"] callWithArguments:@[result]];

JavaScript

function showResult(resultNumber)
{
   document.getElementById("result").innerText = resultNumber;
}

三、WKWebView && JavaScript >=iOS8
iOS 8引入了一個(gè)新的框架——WebKit映跟,之后變得好起來(lái)了蓄拣。在WebKit框架中,有WKWebView可以替換UIKit的UIWebView和AppKit的WebView努隙,而且提供了在兩個(gè)平臺(tái)可以一致使用的接口球恤。WebKit框架使得開(kāi)發(fā)者可以在原生App中使用Nitro來(lái)提高網(wǎng)頁(yè)的性能和表現(xiàn),Nitro就是Safari的JavaScript引擎 WKWebView 不支持JavaScriptCore的方式但提供message handler的方式為JavaScript 與Native通信.

1.Objective-C 調(diào)用JavaScript

/執(zhí)行html 已經(jīng)存在的js方法
- (IBAction)exeFuncTouched:(id)sender {
    [self.myWebView evaluateJavaScript:@"showAlert('hahahha')"  completionHandler:^(id item, NSError * _Nullable error) {
        
    }];
}
  1. JavaScript 調(diào)用 Objective-C
    JavaScript荸镊,簡(jiǎn)單的封裝一下咽斧,‘Native’為事先在Objective-C注冊(cè)注入的js對(duì)象
function callOC(func,param){
        var url= "func=" + func;
        for(var i in param)
        {
         url = url + "&" + i + "=" + param[i];
        }
        window.webkit.messageHandlers.Native.postMessage(url);
 }

JavaScript調(diào)用

<input type="button" value="打個(gè)招呼" onclick="callOC('alert',{'message':'你好么'})" />

Objective-C實(shí)現(xiàn)

WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
config.userContentController = [[WKUserContentController alloc] init];
// 注入JS對(duì)象Native,
// 聲明WKScriptMessageHandler 協(xié)議
[config.userContentController addScriptMessageHandler:self name:@"Native"];
self.myWebView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
self.myWebView.UIDelegate = self;
[self.view addSubview:self.myWebView];
-(void)userContentController:(WKUserContentController *)userContentController
     didReceiveScriptMessage:(WKScriptMessage *)message {
   if ([message.name isEqualToString:@"Native"]) {
       NSLog(@"message.body:%@", message.body);
       //如果是自己定義的協(xié)議, 再截取協(xié)議中的方法和參數(shù), 判斷無(wú)誤后在這里手動(dòng)調(diào)用oc方法
       NSMutableDictionary *param = [self queryStringToDictionary:message.body];
       NSLog(@"get param:%@",[param description]);
       
       NSString *func = [param objectForKey:@"func"];
       
       //調(diào)用本地函數(shù)
       if([func isEqualToString:@"alert"])
       {
           [self showMessage:@"來(lái)自網(wǎng)頁(yè)的提示" message:[param objectForKey:@"message"]];
       }
   }
}

轉(zhuǎn)載地址:http://www.skyfox.org/javascript-ios-navive-message.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末躬存,一起剝皮案震驚了整個(gè)濱河市张惹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌岭洲,老刑警劉巖宛逗,帶你破解...
    沈念sama閱讀 217,084評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異盾剩,居然都是意外死亡雷激,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)告私,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)屎暇,“玉大人,你說(shuō)我怎么就攤上這事驻粟「浚” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,450評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)挤巡。 經(jīng)常有香客問(wèn)我剩彬,道長(zhǎng),這世上最難降的妖魔是什么玄柏? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,322評(píng)論 1 293
  • 正文 為了忘掉前任襟衰,我火速辦了婚禮,結(jié)果婚禮上粪摘,老公的妹妹穿的比我還像新娘。我一直安慰自己绍坝,他們只是感情好徘意,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著轩褐,像睡著了一般椎咧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上把介,一...
    開(kāi)封第一講書(shū)人閱讀 51,274評(píng)論 1 300
  • 那天勤讽,我揣著相機(jī)與錄音,去河邊找鬼拗踢。 笑死脚牍,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的巢墅。 我是一名探鬼主播诸狭,決...
    沈念sama閱讀 40,126評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼君纫!你這毒婦竟也來(lái)了驯遇?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,980評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蓄髓,失蹤者是張志新(化名)和其女友劉穎叉庐,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體会喝,經(jīng)...
    沈念sama閱讀 45,414評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡陡叠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了好乐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片匾竿。...
    茶點(diǎn)故事閱讀 39,773評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蔚万,靈堂內(nèi)的尸體忽然破棺而出岭妖,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,470評(píng)論 5 344
  • 正文 年R本政府宣布昵慌,位于F島的核電站假夺,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏斋攀。R本人自食惡果不足惜已卷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望淳蔼。 院中可真熱鬧侧蘸,春花似錦、人聲如沸鹉梨。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,713評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)存皂。三九已至晌坤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間旦袋,已是汗流浹背骤菠。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,852評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留疤孕,地道東北人商乎。 一個(gè)月前我還...
    沈念sama閱讀 47,865評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像胰柑,于是被迫代替她去往敵國(guó)和親截亦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評(píng)論 2 354

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