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) {
}];
}
- 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