一、webView 的两个方法实现 OC 与 JS 的交互
在 iOS7之前主要使用这种方案
//实现 OC 调用 JS 的代码
- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
// 与 web 端定好协议,拦截参数 request ,根据参数来执行不同的 OC 代码
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
1、OC 调用 JS 的代码
辅助代码:
#import "ViewController.h"
@interface ViewController ()<UIWebViewDelegate>
@property (nonatomic,strong) UIWebView * webView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIWebView * webView = [[UIWebView alloc] initWithFrame:[UIScreen mainScreen].bounds];
webView.delegate = self;
self.webView = webView;
NSURL * url = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"html"];
NSURLRequest * urlRequest = [NSURLRequest requestWithURL:url];
[webView loadRequest:urlRequest];
[self.view addSubview:webView];
}
在代理方法中实现 OC 执行 JS 代码:
// 实现 OC 执行 JS 代码
- (void)webViewDidFinishLoad:(UIWebView *)webView{
NSString * alertJs = @"alert('test js OC')";
[webView stringByEvaluatingJavaScriptFromString:alertJs];
}
2、JS 调用 OC 的代码
test.html代码:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<p></p>
<div>
<button onclick="open_camera();">拍照</button>
</div>
<p></p>
<div>
<button onclick="call();">打电话</button>
</div>
<script>
function open_camera() {
// 定好的协议wb://
window.location.href = 'wb://openCamera';
}
</script>
</body>
</html>
在js 的函数中定好协议,截取协议中的字符串,根据字符串对应的方法执行相应的 OC 代码
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
NSString * url = request.URL.absoluteString;
NSRange range = [url rangeOfString:@"wb://"];
NSUInteger loc = range.location;
if (loc != NSNotFound) {
// 方法名
NSString * method = [url substringFromIndex:loc + range.length];
// 转成 SEL
SEL sel = NSSelectorFromString(method);
[self performSelector:sel];
}
return YES;
}
- (void)openCamera{
NSLog(@"%s",__func__);
}
点击拍照打印:
方案一是比较 low 的方法,项目推荐使用方案二用JavaScriptCore框架。
二、用 JavaScriptCore 框架
iOS7引入了JS框架<JavaScriptCore/JavaScriptCore.h>,给了“纯iOS程序员”一个枯木逢春的契机~学习强大的 JavaScript。
导入<JavaScriptCore/JavaScript.h>可以看到包含五个类:JSContext
、JSValue
、JSManagedValue
、JSVirtualMachine
、JSExport
。
开发中 JS 和 OC 的交互主要用 JSContext
JSValue
JSExport
。
-
JSContext
就为JS提供了运行的环境。通- (JSValue *)evaluateScript:(NSString *)script;
方法就可以执行一段JavaScript脚本,并且其中的方法、变量等信息都会被存储在其中以便在需要的时候使用。 -
JSValue
在 Objective-C 对象和 JavaScript 对象之间起转换作用
1、OC 执行 JS 代码
思路:
1、建立 context 运行环境
2、context 执行 js代码(执行之后变量,函数都保存在 context 中了)
3、取出 context 中的函数保存在 JSValue 中
4、JSValue 执行 callWithArguments: 方法传递参数
- (void)OCExcuteJS{
NSString * path = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"js"];
NSString * testScript = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
//1、创建js执行的环境
JSContext * context = [[JSContext alloc] init];
// 2、context 执行 js 代码后,里面的变量,函数都存在其中,在使用的时候直接用下标调用即可
[context evaluateScript:testScript];
// 3、取出 context中的 factorial 中的方法
JSValue *function = context[@"factorial"];
// 4、JSValue 是函数,执行代码
JSValue *result = [function callWithArguments:@[@10]];
NSLog(@"factorial(10) = %@, 类型转换后的:%d",result,[result toInt32]);
}
结果:
2、JS 执行 OC 代码
JS 执行 OC 代码有两种方案:
- block :对应 JS 的函数
- JSExport协议:对应 JS 的对象
1)block--->JS 函数
思路:
1、创建 JSContext 环境
2、给 JS 增加一个test函数
3、js 代码
4、context 执行 js 代码
- (void)JSExcuteOC_block{
// 1.创建 JSContext环境
JSContext * context = [[JSContext alloc] init];
// 2.给 JS 代码增加一个 test 函数
context[@"test"] = ^(){
NSArray * args = [JSContext currentArguments];
for (id obj in args) {
NSLog(@"obj = %@",obj);
}
};
// 3.JS 函数执行
NSString * jsFuncstr = @"test('参数1','参数2')";
// 4.执行 JS代码
[context evaluateScript:jsFuncstr];
}
执行结果:
补充:
1、不要在 Block 中直接使用外面的 JSValue 对象, 把 JSValue 当做参数来传进 Block 中。
2、避免循引用,不要在 Block 中直接引用使用外面的 JSContext 对象,应该用[JSContext currentContext];
2)JSExport---->JS对象
只要是添加了JSExport协议的协议,所规定的方法,变量等就会对js开放,我们可以通过js调用到。
遵循 JSExport 的类
#person.h 文件
#import <Foundation/Foundation.h>
@import JavaScriptCore;
@protocol PersonProtocol <JSExport>
//此处我们测试几种参数的情况
-(void)TestNOParameter;
-(void)TestOneParameter:(NSString *)message;
-(void)TestTowParameter:(NSString *)message1 SecondParameter:(NSString *)message2;
@end
@interface Person : NSObject<PersonProtocol>
@end
#person.m文件
#import "Person.h"
@implementation Person
//一下方法都是只是打了个log 等会看log 以及参数能对上就说明js调用了此处的iOS 原生方法
-(void)TestNOParameter
{
NSLog(@"this is ios TestNOParameter");
}
-(void)TestOneParameter:(NSString *)message
{
NSLog(@"this is ios TestOneParameter=%@",message);
}
-(void)TestTowParameter:(NSString *)message1 SecondParameter:(NSString *)message2
{
NSLog(@"this is ios TestTowParameter=%@ Second=%@",message1,message2);
}
@end
执行
// 1、创建 OC遵循 JSExport的对象
Person * person = [[Person alloc] init];
// 2、创建 context 环境
JSContext * context = [[JSContext alloc] init];
// 3、为 JS 添加一个对象
context[@"person"] = person;
// 4、执行 OC 中对应的方法
NSString *jsStr1=@"person.TestNOParameter()";
[context evaluateScript:jsStr1];
NSString *jsStr2=@"person.TestOneParameter('参数1')";
[context evaluateScript:jsStr2];
NSString *jsStr3=@"person.TestTowParameterSecondParameter('参数A','参数B')";
[context evaluateScript:jsStr3];
结果:
参考:
http://blog.csdn.net/lwjok2007/article/details/47058795
http://blog.csdn.net/lizhongfu2013/article/details/9232129