Objective-C调用javascript
一.stringByEvaluatingJavaScriptFromString 方法可以将javascript嵌入页面中,通过这个方法我们可以在iOS中与UIWebView中的网页元素交互,需要等UIWebView中的页面加载完成之后去调用。
//插入js 并且执行传值
-(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(); "];
}
//修改标签属性
- (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代码直接的交互变得更加的简单方便。
合适时机注入交互对象
什么时候UIWebView会创建JSContext环境?
分两种方式
第一在渲染网页时遇到<script标签时,就会创建JSContext环境去运行JavaScript代码。
第二就是使用方法
[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]去获取JSContext环境时,这时无论是否遇到<script标签,都会去创造出来一个JSContext环境,而且和遇到<script标签再创造环境是同一个。
什么时候注入JSContext问题
我通常都会在 - (void)webViewDidFinishLoad:(UIWebView *)webView中去注入交互对象,但是这时候网页还没加载完,JavaScript那边已经调用交互方法,这样就会调不到原生应用的方法而出现问题。
改成在- (void)viewDidLoad中去注入交互对象,这样倒是解决了上面的问题,但是同时又引起了一个新的问题就是在一个网页内部点击链接跳转到另一个网页的时候,第二个页面需要交互,这时JSContext环境已经变化,但是- (void)viewDidLoad仅仅加载一次,跳转的时候,没有再次注入交互对象,这样就会导致第二个页面没法进行交互。当然你可以在- (void)viewDidLoad和- (void)webViewDidFinishLoad:(UIWebView *)webView都注入一次,但是一定会有更优雅的办法去解决此问题。
如果上边的方案能满足需求,建议实在迫不得已再用这个方法, 就是在每次创建JSContext环境的时候,我们都去注入此交互对象这样就解决了上面的问题。具体解决办法参考了此开源库UIWebView-TS_JavaScriptContext。
多个iFrame中的JSContext问题
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调用Objective-C UIWebview的delegate
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
// 以 html title 设置 导航栏 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 协议关联 native 的方法
self.context[@"app"] = self;
// 以 block 形式关联 JavaScript function
self.context[@"log"] =
^(NSString *str)
{
NSLog(@"%@", str);
};
//多参数
self.context[@"mutiParams"] =
^(NSString *a,NSString *b,NSString *c)
{
NSLog(@"%@ %@ %@",a,b,c);
};
}
2.Objective-C 调用 JavaScriptCore
Objective-C
调用js的showResult方法,这里是一个参数 result,多个就依次写到数组中
[self.context[@"showResult"] callWithArguments:@[result]];
JavaScript
function showResult(resultNumber)
{
document.getElementById("result").innerText = resultNumber;
}
三、WKWebView && JavaScript >=iOS8
iOS 8引入了一个新的框架——WebKit,之后变得好起来了。在WebKit框架中,有WKWebView可以替换UIKit的UIWebView和AppKit的WebView,而且提供了在两个平台可以一致使用的接口。WebKit框架使得开发者可以在原生App中使用Nitro来提高网页的性能和表现,Nitro就是Safari的JavaScript引擎 WKWebView 不支持JavaScriptCore的方式但提供message handler的方式为JavaScript 与Native通信.
1.Objective-C 调用JavaScript
/执行html 已经存在的js方法
- (IBAction)exeFuncTouched:(id)sender {
[self.myWebView evaluateJavaScript:@"showAlert('hahahha')" completionHandler:^(id item, NSError * _Nullable error) {
}];
}
- JavaScript 调用 Objective-C
JavaScript,简单的封装一下,‘Native’为事先在Objective-C注册注入的js对象
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调用
<input type="button" value="打个招呼" onclick="callOC('alert',{'message':'你好么'})" />
Objective-C实现
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
config.userContentController = [[WKUserContentController alloc] init];
// 注入JS对象Native,
// 声明WKScriptMessageHandler 协议
[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);
//如果是自己定义的协议, 再截取协议中的方法和参数, 判断无误后在这里手动调用oc方法
NSMutableDictionary *param = [self queryStringToDictionary:message.body];
NSLog(@"get param:%@",[param description]);
NSString *func = [param objectForKey:@"func"];
//调用本地函数
if([func isEqualToString:@"alert"])
{
[self showMessage:@"来自网页的提示" message:[param objectForKey:@"message"]];
}
}
}
转载地址:http://www.skyfox.org/javascript-ios-navive-message.html