The quiter you become,the more you are able to hear!

iOS JavaScriptCore 简单使用

Author: geneblue

Blog: https://geneblue.github.io/

介绍

apple 从 iOS7.0 开始增加了 JavaScriptCore 框架。该框架提供了在 Swift,Objective-C 和 C 这些 native code 中执行 javascript 脚本的能力,当然,也支持将 native object 插入到 js 的执行环境中。

demo

JavaScriptCore 框架的使用非常简单,看以下 demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#import <JavaScriptCore/JavaScriptCore.h>

{
//创建虚拟机
JSVirtualMachine *vm = [[JSVirtualMachine alloc] init];

//创建上下文
JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm];

//执行JavaScript代码并获取返回值
JSValue *value = [context evaluateScript:@"1+2*3"];

//转换成OC数据并打印
NSLog(@"value = %d", [value toInt32]);
}

三行代码就建立了一个 js 执行环境并执行一段小脚本。JSVirtualMachine 会为我们建立一个独立的 vm 环境,JSContext 会建立 js 执行的上下文,一个 vm 里可以创建多个 context 环境,而且这些 context 中的 JSValue 可以互相使用。内存管理由 vm 负责,完全不用我们操心的。

关键类介绍

#import <JavaScriptCore/JavaScriptCore.h> 头文件,主要引入以下关键类

1
2
3
4
5
#import "JSContext.h"
#import "JSValue.h"
#import "JSManagedValue.h"
#import "JSVirtualMachine.h"
#import "JSExport.h"

JSVirtualMachine JSContext

建立 vm 环境,建立 context 上下文

JSValue

JSValue 用于在 native 代码和 js 之间传递数据,JSValue 与 context 是一一对应的,可以通过 JSValue 直接拿到对应的 context;当然,JSValue 也提供了很多方法,让 native 和 js 的数据类型进行转换。native 与 js 复杂的数据类型转换,见参考。

JSManagedValue

将JSValue转换为JSManagedValue,则运行时两侧都可以正常访问对象,避免一端释放一端仍然持有的状态。

JSExport

导出OC的函数与属性供JavaScript使用,继承了这个协议的协议中定义的方法,就可以直接在JSContext中被使用

OC 与 JS 的互相交互

OC 调用 JS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 创建 js vm
JSVirtualMachine *jsvm = [JSVirtualMachine new];
// 创建执行 context
JSContext *context = [[JSContext alloc] initWithVirtualMachine:jsvm];

// native 调用 js 代码
// 直接执行 js 代码
JSValue *value = [context evaluateScript:@"1+2*3"];
NSLog(@"value = %d", [value toInt32]);
JSValue *value2 = [context evaluateScript:@"function hi(){ return 'hi' }; hi()"];
NSLog(@"value = %@", [value2 toString]);

// 执行 js 文件中的代码
NSString *path = [[NSBundle mainBundle] pathForResource:@"jscalloc" ofType:@"js"];
NSString *html = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
JSValue *value3 = [context evaluateScript:html];
NSLog(@"value = %@", [value3 toString]);

// 注册 js 方法,然后调用
// 注册函数,调用
[context evaluateScript:@"var hello = function(){ return 'hello' }"];
JSValue *value4 = [context evaluateScript:@"hello()"];
NSLog(@"value = %@", [value4 toString]);

// 注册匿名函数,调用
JSValue *jsFunc = [context evaluateScript:@"(function(){return 'hello objc'})"];
JSValue *value5 = [jsFunc callWithArguments:nil];
NSLog(@"value = %@", [value5 toString]);

JS 调用 OC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 创建 js vm
JSVirtualMachine *jsvm = [JSVirtualMachine new];
// 创建执行 context
JSContext *context = [[JSContext alloc] initWithVirtualMachine:jsvm];

// js 调用 native 代码, 主要注册 native 方法
// 注册一个 obj 方法给 js 调用
context[@"log"] = ^(NSString *msg){
NSLog(@"OCMethod: log called from js: %@", msg);
return @"this is log1";
};

context[@"log2"] = ^() {
NSArray *args = [JSContext currentArguments];
for (id obj in args) {
NSLog(@"OCMethod2: log called from js: %@", obj);
}
};


// 注册完毕,调用
JSValue *value6 = [context evaluateScript:@"log('this is method log')"];
NSLog(@"value = %@", [value6 toString]);


[context evaluateScript:@"log('this is method log2')"];

NSLog(@"this is te");

参考