UIWebView简介
UIWebView
是iOS8之前常用的用来加载H5的控件,iOS8之后出现了WKWebView
,但是如果需要适配iOS7的同学,还是需要用到UIWebView
。
UIWebView加载
HTML代码,将HTML添加到工程中
<html>
<header>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript">
function btnClick() {
ret = JSInvokeOC('args1','args 2','args3');
alert(ret);
}
function btnClick1() {
ret = OCObj.test();
alert(ret);
}
function OCInvokeJS(message){
alert(message);
return 'OCInvokeJS return';
}
</script>
</header>
<body>
<h2> OC&JS相互调用 </h2>
<br/>
<a href="aima://smsLogin?username=110&code=120">JS调用OC之URL拦截</a>
<br/>
<button type="button" onclick="btnClick()">JS调用OC之JSContext-block</button>
<br/>
<button type="button" onclick="btnClick1()">JS调用OC之JSExport</button>
<br/>
</body>
</html>
工程编译后,HTML会在根目录下,加载HTML到WebView
//加载本地MyWebView.html
NSString *basePath = [[NSBundle mainBundle]bundlePath];
NSString *helpHtmlPath = [basePath stringByAppendingPathComponent:@"MyWebView.html"];
NSURL *url = [NSURL fileURLWithPath:helpHtmlPath];
//就是这么简单,load一下就可以了
[self.webView loadRequest:[NSURLRequest requestWithURL:url]];
JS调用OC之URL拦截法
实现UIWebView
下面的代理方法,WebView中发生的每次跳转都会先调用该代理方法,如果返回YES,则正常跳转,如果返回NO,则不跳转
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if ([request.URL.absoluteString containsString:@"aima://smsLogin"]) { //aima://smsLogin?username=110&code=120
NSLog(@"url parameters:%@", request.URL.query); //username=110&code=120
return NO;
}
return YES;
}
JS调用OC之javaScriptCore
javaScriptCore.framework
是从iOS7开始引入的框架,该框架让 Objective-C
和JavaScript
代码直接的交互变得更加的简单方便。
JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
context[@"JSInvokeOC"] = ^(NSString *str1, NSString *str2, NSString *str3) {
NSLog(@"Arguments:%@, %@, %@", str1, str2, str3);
return @"JS调用了OC方法";
};
JS调用OC之JSExport
JSExport
是javaScriptCore.framework
中提供的OC&JS
交互方法,如果说上面JSContext
的block
方法,是对JS暴露一个方法,那么JSExport
就是对JS暴露了一个对象,个人感觉JSExport
的方式对于OC和JS开发者来说都更加规范,代码更加清晰。
首先声明一个自定义的协议并继承自JSExport
协议。
@protocol TestJSExport <JSExport>
- (NSString *)test;
@end
然后实现这个自定义协议,然后JS就能像使用原生对象一样使用OC对象了。
@interface ViewController ()<UIWebViewDelegate, TestJSExport>
@property (weak, nonatomic) IBOutlet UIWebView *webView;
@end
@implementation ViewController
- (void)webViewDidFinishLoad:(UIWebView *)webView {
JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
context[@"OCObj"] = self;
//点击HTML上 JS调用OC之JSExport 按钮,就会调用下面的test方法了
}
- (NSString *)test {
return @"JS 调用了OC的test方法";
}
@end
OC调用JS之UIWebView原生方法
//该方式调用方法简单
//但属于同步方法,会阻塞线程直到返回
//方法虽然未被废弃但帮助文档中已建议放弃该方式
//方法执行错误会直接返回nil
NSString *ret = [self.webView stringByEvaluatingJavaScriptFromString:@"OCInvokeJS('wocao')"];
OC调用JS之javaScriptCore
//获取webView中的JavaScript上下文
JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
NSString *textJS = @"OCInvokeJS('WOCAO')";
//直接调用即可,如果方法未实现会返回'undefined'
//经测试,方法也是同步方法
JSValue *ret = [context evaluateScript:textJS];
参考
深入浅出 JavaScriptCore
iOS中UIWebView与WKWebView、JavaScript与OC交互、Cookie管理看我就够