美文网首页
iOS的JavaScriptCore浅谈

iOS的JavaScriptCore浅谈

作者: 一天天的啊哈哈 | 来源:发表于2021-05-11 20:06 被阅读0次

一直想写一写JavaScriptCore,因为在公司写了很多关于这方面的代码,今天腾出来时间好好说一说,对自己也是个巩固,如果能帮到别人那更好了,如有问题欢迎指出

比较常见的JS引擎有Google的V8(Android,Chrome),还有JSCore(Safari)。Safari的内核就是WebKit

先来看一看JavaScriptCore.h 主要用到的就是这几个类


JavaScriptCore.h

先写个Hello World吧😄

JSContext *jsContext = [[JSContext alloc] init];
    
JSValue *hello = [jsContext evaluateScript:@"'Hello World!'"];
    
NSLog(@"%@",[hello toString]);

这里面包含了JSCore中最重要的两个类,JSContext和JSValue

JSContext

JSContext对象代表一个JavaScript执行环境,我们使用JSContext在原生里去执行JS代码,执行过的JS都会存在当前的JSContext中。

JSContext

我们调用JSContext可以在原生中执行各种JS代码,比如数值运算,对象创建,甚至可以通过JS操作各种原生的API去创建原生的视图等

jsContext[@"nslog"] = ^(NSString* message) {
        NSLog(@"%@", message);
};
[jsContext evaluateScript:@"console.log = nslog;"];

上面是模拟实现原生的NSLog,这样我们在JS代码中使用console.log就会在原生的控制台中打印出内容啦

JSValue

JSValue简单点来讲就是JS里面的值,它可以用作Native和JS之间的类型互换,头文件里已经标明了几种类型

JSValue.h

举几个例子

JSValue *number = [jsContext evaluateScript:@"1+1"];
NSLog(@"%d",[number toInt32]);

JSValue *arr = [jsContext evaluateScript:@"['ha','haha','hahaha']"];
NSLog(@"%@",[arr toArray]);

也可以这样使用

[jsContext evaluateScript:@"var num = 1 + 1"];
JSValue *number = jsContext[@"num"];
NSLog(@"%d",[number toInt32]);

[jsContext evaluateScript:@"var dic = {r:255,g:127,b:80}"];
JSValue *dic = jsContext[@"dic"];
NSLog(@"%@",[dic toDictionary]);

JSVirtualMachine

一个JSVirtualMachine的实例就是一个完整独立的JavaScript的执行环境,它主要用于实现JSCore的并发执行,以及内存管理

回到开头的HelloWorld,可以这么写

JSVirtualMachine *jvm = [[JSVirtualMachine alloc] init];
    
JSContext *jsContext = [[JSContext alloc] initWithVirtualMachine:jvm];
    
JSValue *hello = [jsContext evaluateScript:@"'Hello World!'"];

NSLog(@"%@",[hello toString]);

每个JSContext都属于一个虚拟机JSVirtualMachine,一个虚拟机可以包含多个JSContext。然而多个虚拟机之间是相对独立的,以此来实现JSCore的并发执行。

JSVirtualMachine *jvm = [[JSVirtualMachine alloc] init];
JSVirtualMachine *jvm2 = [[JSVirtualMachine alloc] init];
JSContext *jsContext = [[JSContext alloc] initWithVirtualMachine:jvm];
JSContext *jsContext2 = [[JSContext alloc] initWithVirtualMachine:jvm2];
    
// 串行队列
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);

// 异步执行
dispatch_async(queue, ^{
    [[NSThread currentThread] setName:@"thread--1"];
    for (int i = 0; i < 3; i++) {
        NSLog(@"串行异步1 %@  %@",[[jsContext evaluateScript:@"'thread---1'"] toString],[NSThread currentThread]);
    }
});
dispatch_async(queue, ^{
    [[NSThread currentThread] setName:@"thread--2"];
    for (int i = 0; i < 3; i++) {
        NSLog(@"串行异步2 %@  %@",[[jsContext2 evaluateScript:@"'thread---2'"] toString],[NSThread currentThread]);
    }
});

JSExport

JSExport可以将native完整提供给JS环境

native类实现JSExport协议 将想要提供的属性或方法提供出来

@protocol NativeExport <JSExport>

@property (nonatomic,copy) NSString *str;

- (void)method;

- (void)method2:(NSString *)str;

@end
// 在类中实现该协议
@interface NativeObject : NSObject<NativeExport>

@end

实现该方法

- (void)method {
    NSLog(@"call native");
}

- (void)method2:(NSString *)str {
    NSLog(@"%@",str);
}

将类对象注入到JS环境中,JS可以随意定义一个变量来接收它

jsContext[@"native"] = [[NativeObject alloc] init];

调用一下试试

[jsContext evaluateScript:@"native.method()"];
[jsContext evaluateScript:@"native.method2('hello')"];
控制台

如果要在提供的native类里面注入,也可以这么写,不过要记得释放

@implementation NativeObject

- (instancetype)init {
    if (self = [super init]) {
        jsContext[@"native"] = self;
    }
    return self;
}

@end
//要记得释放它
- (void)closeContext {
    self.jsContext[@"native"] = nil;
}

相关文章

网友评论

      本文标题:iOS的JavaScriptCore浅谈

      本文链接:https://www.haomeiwen.com/subject/bljpcltx.html