前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >全面解析 JavaScriptCore 相关特性

全面解析 JavaScriptCore 相关特性

作者头像
网罗开发
发布2021-01-29 16:02:24
1.2K0
发布2021-01-29 16:02:24
举报
文章被收录于专栏:网罗开发

前言


目前越来越多的移动应用采用 Hybird App 模式来开发,即混合了 Native 技术与 Web 技术 进行开发。在 iOS 开发中,JavaScriptCore 框架支持 JS 与 OC 直接互相调用,从而实现动态化方案。

框架简介


JavaScriptCore 框架是苹果在 iOS7 引入的一个框架,该框架让 Objective-C 和 JavaScript 代码 互通,即支持在 Objective-C 中执行 js 代码,也支持js代码中执行 OC 代码。

浏览器中能执行JS脚本是因为浏览器中内置了 JavaScript 引擎。JavaScriptCore 是苹果Safari 浏览器的 JavaScript 引擎,而JavaScriptCore框架是基于 Objective-C 实现了对 JavaScriptCore 的封装,提供了Objective-C 接口,让开发者能够在在iOS App 中处理 JavaScript 脚本。

简单使用


先来简单了解下在 iOS Native 开发中如何使用 JavaScriptCore 框架

代码语言:javascript
复制
    #import "JavaScriptCore/JavaScriptCore.h" // 引入头文件
    ...
    ...
    // 创建一个JSContext对象
    JSContext *jsContext = [[JSContext alloc] init];

    // 执行JS代码 计算js变量a和b之和
    [jsContext evaluateScript:@"var a = 1;var b = 2;"];
    JSValue *result = [jsContext evaluateScript:@"a + b"];
    NSInteger sum = [result toInt32];
    NSLog(@"%ld", (long)sum);    // 3

上面代码中做了如下几件事情

  1. 引入"JavaScriptCore/JavaScriptCore.h" 头文件
  2. 创建了一个JSContext 类对象 jsContext
  3. jsContext 调用evaluateScript: 方法执行了两条 js 语句,并得到执行结果 result,是一个 JSValue 类对象
  4. result调用 toInt32 方法,返回数值类型的 sum 并打印,输出结果为 3。
  5. 这里涉及了 JavaScriptCore 框架中的两个核心类:JSContext 类 和 JSValue类。这里先说明下他们的作用,后续再详细介绍。

JSContext 类: 一个 JSContext 表示了一次JS的执行环境。在 iOS 开发中,可以通过创建一个 JSContext 去调用 JS 脚本,访问一些JS定义的值和函数,同时也提供了让 JS 访问 Native 对象、方法的接口。

JSValue 类: JS 侧的代码执行结果都可以从 JSContext 中获取然后赋值给 JSValue对象,JSValue 是保证 JS 端和 Native 的方法能互相调用的桥梁。

框架详解


JavaScriptCore 框架包含的头文件真的是非常的少,如下所示,

下面是整个框架的结构图

下面对各个文件逐一分析

JavaScript 和 JavaScriptCore
▐ JSContent
JSValue
JSManagedValue

JSExport
JSVirtualMachine

更多使用


OC 代码中执行 JS 语句
代码语言:javascript
复制
- (void)ocEvaluateScript {
    // 创建一个JSContext对象
    JSContext *jsContext = [[JSContext alloc] init];

    // 执行JS代码 计算js变量a和b之和
    [jsContext evaluateScript:@"var a = 1;var b = 2;"];
    NSInteger sum = [[jsContext evaluateScript:@"a + b"] toInt32];
    NSLog(@"%ld", (long)sum);    // 3

    // 通过下标获取变量、方法
    [jsContext evaluateScript:@"var names = ['Same','Jack','Bob']"];
    JSValue *names = jsContext[@"names"];
    JSValue *initialName = names[0];
    NSLog(@"%@", initialName.toString); // 'Same'

    // 定义方法并调用
    [jsContext evaluateScript:@"var addFunc = function(a, b) { return a + b }"];
    JSValue *result = [jsContext evaluateScript:@"addFunc(a, b)"];
    NSLog(@"%@", result.toNumber);  // 3

    // 也可以OC传参
    JSValue *addFunc = jsContext[@"addFunc"];
    JSValue *addResult = [addFunc callWithArguments:@[@10, @30]];
    NSLog(@"%d", addResult.toInt32);    // 40
}
OC 代码中执行 JS 脚本内容

ocEvaluateScript.js 脚本

代码语言:javascript
复制
function subtractFunc(a, b) {
    return a - b;
}
console.log(subtractFunc(15, 7))
console.log("Hello ocEvaluateScript")

OC 代码中加载 ocEvaluateScript.js 脚本并执行

代码语言:javascript
复制
- (void)ocEvaluateScriptFile {
    JSContext *jsContext = [[JSContext alloc] init];
    NSString *path = [[NSBundle mainBundle] pathForResource:@"ocEvaluateScript" ofType: @"js"];
    NSString *layoutJS = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
    [jsContext evaluateScript:layoutJS];

    JSValue *subtractFunc = jsContext[@"subtractFunc"];
    JSValue *subtractResult = [subtractFunc callWithArguments:@[@20, @10]];
    NSLog(@"%d", subtractResult.toInt32);    // 10
}
  1. OC 代码中加载并执行了 ocEvaluateScript.js,然后调用了 subtractFunc 方法,控制台输出结果为 10;
  2. 打开 safari 浏览器,运行程序后,会弹出网页检查器,其控制台输出ocEvaluateScript.js 脚本的执行结果
JS 脚本执行 OC 代码

scriptEvaluateOC.js 脚本内容,addFunc 方法和 subtractFun 方法是在 OC 代码中定义的。

代码语言:javascript
复制
console.log(addFunc(5, 5))
console.log(subtractFunc(8, 5))
console.log("Hello scriptEvaluateOC")

OC 代码中定义 addFunc 方法和 subtractFun 方法,并加载执行 scriptEvaluateOC.js

代码语言:javascript
复制
- (void)scriptEvaluateOC {
    JSContext *jsContext = [[JSContext alloc] init];
    jsContext[@"addFunc"] = ^(NSInteger a, NSInteger b) {
        return a + b;
    };
    JSValue *addResult = [jsContext evaluateScript:@"addFunc(3, 4)"];
    NSLog(@"%@", addResult.toNumber);  // 7

    // setObject:forKeyedSubscript:方法用来向JSContext环境的全局对象中添加属性
    [jsContext setObject:^(NSInteger a, NSInteger b) {
        NSArray *args = [JSContext currentArguments];
        NSLog(@"argu are %@", args);
        return a - b;
    } forKeyedSubscript:@"subtractFunc"];
    JSValue *subtractResult = [jsContext evaluateScript:@"subtractFunc(4, 3)"];
    NSLog(@"%@", subtractResult.toNumber);  // 1

    NSString *path = [[NSBundle mainBundle] pathForResource:@"scriptEvaluateOC" ofType: @"js"];
    NSString *layoutJS = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
    [jsContext evaluateScript:layoutJS];
}

打开 safari 浏览器,运行程序后,会弹出网页检查器,其控制台输出scriptEvaluateOC.js 脚本的执行结果

Native UI 动态化方案


Native UI 动态化是指在 js 脚本中编写 Native 的 UI 信息,然后由 Native 加载执行,解析转换成 Native 的 UI 实现。这种方案可以支持 js 层做了关于渲染信息的一些修改后,Native 只要重新加载执行js就可以更新 UI 信息而不需要重新编译,打包发版。这里简单的实现一个 UILabel 标签的示例来说明下思路 view.js

代码语言:javascript
复制
 (function(){
  return render();
  })();

//JS标签类
function Label(rect,text,color){
    this.rect = rect;
    this.text = text;
    this.color = color;
    this.typeName = "Label";
}

//JS Rect类
function Rect(x,y,width,height){
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
}

//渲染方法 界面的渲染写在这里面
function render(){
    var rect = new Rect(20,100,280,30);
    var label = new Label(rect,"Hello World", "0xff0000");
    return label
}

Native 逻辑在 ViewController.m 中定义 render 方法并执行,主要逻辑如下:

代码语言:javascript
复制
#define HEXCOLOR(hexValue)              [UIColor colorWithRed : ((CGFloat)((hexValue & 0xFF0000) >> 16)) / 255.0 green : ((CGFloat)((hexValue & 0xFF00) >> 8)) / 255.0 blue : ((CGFloat)(hexValue & 0xFF)) / 255.0 alpha : 1.0]
#define HEXACOLOR(hexValue, alphaValue) [UIColor colorWithRed : ((CGFloat)((hexValue & 0xFF0000) >> 16)) / 255.0 green : ((CGFloat)((hexValue & 0xFF00) >> 8)) / 255.0 blue : ((CGFloat)(hexValue & 0xFF)) / 255.0 alpha : (alphaValue)]

-(void)render {
    NSString *path = [[NSBundle mainBundle] pathForResource:@"view" ofType: @"js"];
    NSString *layoutJS = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];

    JSContext *jsContext = [[JSContext alloc] init];
    JSValue * subValue = [jsContext evaluateScript:layoutJS];

    UILabel * label = [UILabel new];
    label.frame = CGRectMake(subValue[@"rect"][@"x"].toDouble, subValue[@"rect"][@"y"].toDouble, subValue[@"rect"][@"width"].toDouble, subValue[@"rect"][@"height"].toDouble);
    label.text = subValue[@"text"].toString;
    label.textColor = HEXCOLOR(subValue[@"color"].toInt32);
    [self.view addSubview:label];
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 网罗开发 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ▐ JavaScript 和 JavaScriptCore
  • ▐ JSContent
  • ▐ JSValue
  • ▐ JSManagedValue
  • ▐ JSExport
  • ▐ JSVirtualMachine
  • ▐ OC 代码中执行 JS 语句
  • ▐ OC 代码中执行 JS 脚本内容
  • ▐ JS 脚本执行 OC 代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档