JavaScriptCore.framework,是Apple在IOS7.0系统中新加入的一个框架,通过这个框架,Object-c与JavaScript的交互变得简单起来。
(如果对JavaScript不是很熟的可以看下这个网站,http://www.w3school.com.cn/js/js_variables.asp)
先来了解下JavaScriptCore.framework。下图是该框架的Header文件。
Object-C调用JavaScript
JSContext/JSValue
JSContext是运行JavaScript代码的环境,一个JSContext是一个全局环境的实例。通过JSContext就可以运行JavaScript代码,可以创建变量,定义方法等。
下面是一个简单的调用。
JSContext *context = [[JSContext alloc] init];
//数字和方法
[context evaluateScript:@"var num = 5 + 3"];
[context evaluateScript:@"var newNum = function(value) { return value * 5 }"];
JSValue *tripleNum = [context evaluateScript:@"newNum(num)"];
int result = [tripleNum toInt32];
NSLog(@"tripleNum = %d",result);
//字符串
[context evaluateScript:@"var name = 'test'"];
JSValue *name = [context evaluateScript:@"name"];
NSString * ocName = [name toString];
NSLog(@"ocName = %@",ocName);
//数组
[context evaluateScript:@"var ary_Name = ['ss','xx','tt']"];
JSValue * ary_Name = context[@"ary_Name"];
JSValue * jsv_name = ary_Name[2];
NSString * name_three = [jsv_name toString];
NSLog(@"name_three = %@",name_three);
任何出自JSContext的值都被存放在一个JSValue对象中。
JSValue 包括一系列方法用于访问其可能的值以保证有正确的 Foundation 类型,包括:
JSValue 包括一系列方法用于访问其可能的值以保证有正确的 Foundation 类型,包括:
对 JSContext 和 JSValue 实例使用下标的方式我们可以很容易地访问我们之前创建的 context 的任何值。JSContext 需要一个字符串下标,而 JSValue 允许使用字符串或整数标来得到里面的对象和数组
调用方法
我们可以在Object-c或者swift中使用Foundation类型作为参数来调用JavaScript中的函数,比如上段代码中的newNum函数
//方法调用
JSValue * newNumFunction = context[@"newNum"];
JSValue * newNumResult = [newNumFunction callWithArguments:@[@5]];
result = [newNumResult toUInt32];
NSLog(@"result = %d",result);
错误处理
在JSContext中,
exceptionHandler是一个接收JSContext引用和异常本身的回调处理,我们可以观察和记录语法,类型以及运行时错误。
//错误记录
context.exceptionHandler = ^(JSContext * context, JSValue * exception){
NSLog(@"js error = %@",exception);
};
以上是我们在Object-c中调用JavaScript的变量和方法。
JavaScript调用Object-c
让
JSContext
访问我们的本地客户端代码的方式主要有两种:block 和
JSExport
协议
block
一个简单的JS调用Object-c的计算方法
context[@"simpleCalculate"] = ^(NSString * inputString, int numA, int numB){
NSString * result = @"wrong calculate symbol";
if ([inputString isEqualToString:@"+"]) {
result = [NSString stringWithFormat:@"%d",numA + numB];
}else if ([inputString isEqualToString:@"-"]){
result = [NSString stringWithFormat:@"%d",numA - numB];
}else if ([inputString isEqualToString:@"*"]){
result = [NSString stringWithFormat:@"%d",numA * numB];
}else if ([inputString isEqualToString:@"/"]){
result = [NSString stringWithFormat:@"%d",numA / numB];
}
return result;
};
NSLog(@"%@",[context evaluateScript:@"simpleCalculate('*','5','3')"]);
试试修改UI层
//试试修改OC的UI层
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setFrame:CGRectMake(100, 100, 200, 50)];
[button setBackgroundColor:[UIColor orangeColor]];
[self.view addSubview:button];
context[@"changeTitle"] = ^(NSString * title){
[button setTitle:title forState:UIControlStateNormal];
};
[context evaluateScript:@"changeTitle('我是测试按钮')"];
JSExport协议
JSExport是Object-c和JavaScript两种语言的互通协议,继承了该协议的协议都可以在JSContext中被使用。
下面是一个修改UIButton的title的协议,该协议继承了JSExport
@protocol UIButtonExport <JSExport>
- (void)setBackgroundColor:(UIColor *)color;
- (void)setTitle:(NSString *)title forState:(UIControlState)state;
@end
//试试修改OC的UI层
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setFrame:CGRectMake(100, 100, 200, 50)];
[button setBackgroundColor:[UIColor orangeColor]];
[self.view addSubview:button];
context[@"changeTitle"] = ^(NSString * title){
[button setTitle:title forState:UIControlStateNormal];
};
[context evaluateScript:@"changeTitle('我是测试按钮')"];
//对已定义的类添加协议 需要引入#import <objc/runtime.h>
class_addProtocol([UIButton class], @protocol(UIButtonExport));
context[@"button"] = button;
[context evaluateScript:@"button.setTitleForState('hello js','0')"];
注意,对于Object-c中多参数的方法,JavaScriptCore处理的方法是将Object-c方法每个部分都合并,将冒号移除且冒号后面的字母大写,上面代码最后一行的setTitleForState就是这样。如果希望换一个较短的方法名,可以调用
JSExportAs(PropertyName, Selector)这个宏。
JSExportAs(changeTitle, - (void)setTitle:(NSString *)title forState:(UIControlState)state);
context[@"button"] = button;
// [context evaluateScript:@"button.setTitleForState('hello js','0')"];
[context evaluateScript:@"button.changeTitle('hello js','0')"];
一个简单的通过JavaScript获取当前时间并实时更新到UIButton的Title上的代码
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setFrame:CGRectMake(10, 100, 300, 50)];
[button setBackgroundColor:[UIColor orangeColor]];
button.titleLabel.font = [UIFont systemFontOfSize:12.0f];
[button addTarget:self action:@selector(repeatsChange) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
- (void)repeatsChange{
NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(changeTitle) userInfo:nil repeats:YES];
[timer fire];
}
- (void)changeTitle{
UIButton * btn;
for (UIButton * button in self.view.subviews) {
if (button) {
btn = button;
}
}
JSContext * context = [[JSContext alloc]init];
context[@"btn"] = btn;
[context evaluateScript:@"var now = new Date()"];//JS获取当前时间
// [context evaluateScript:@"var num = now.getSeconds()"];
[context evaluateScript:@"btn.changeTitle(now,'0')"];
}
后续有了解的话继续补充