让你的iOS应用程序支持运行JavaScript脚本:JavaScriptCore框架详解(一)-阿里云开发者社区

开发者社区> 珲yy少> 正文

让你的iOS应用程序支持运行JavaScript脚本:JavaScriptCore框架详解(一)

简介: 让你的iOS应用程序支持运行JavaScript脚本:JavaScriptCore框架详解
+关注继续查看

 说到JavaScript脚本,iOS开发者都会想到一个名叫JavaScriptCore的框架。这个框架的确十分强大,其中封装了一套JavaScript运行环境以及Native与JS数据类型之间的转换桥梁。本篇博客主要讨论如何使用此框架来在iOS应用中运行JavaScript脚本。


一、JavaScriptCore框架结构


   在学习一个框架时,首先应该先了解整个框架的结构,拿iOS开发来举例,对于一个陌生的框架,第一步需要先搞清楚这里面都包含哪些类,个各类之间是怎样的关系,这个框架和其他的框架间有无联系以及怎样产生的联系。将些问题搞清楚,有了大体上的认识后,我们再来学习其中的每个类即其他细节的应用将非常容易。我们先来看一张JavaScriptCore框架的结构图:


image.png


这张图是我手工画的,不是那么美观并且没有文字的解释,但是我觉得它能非常直观的表达JavaScriptCore中包含的类之间的关系。下面我来向你解释这张图究竟表达了什么意思,首先原生的iOS应用是支持多线程执行任务的,我们知道JavaScript是单线程,但这并不代表我们不能在Native中异步执行不同的JavaScript代码。


1.JSVirtualMachine——JavaScript的虚拟机


   JavaScriptCore中提供了一个名为JSVirtualMachine的类,顾名思义,这个类可以理解为一个JS虚拟机。在Native中,只要你愿意,你可以创建任意多个JSVirtualMachine对象,各个JSViretualMachine对象间是相互独立的,他们之间不能共享数据也不能传递数据,如果你把他们放在不同的Native线程,他们就可以并行的执行无关的JS任务。


2.JSContext——JavaScript运行环境


   JSContext上下文对象可以理解为是JS的运行环境,同一个JSVirtualMachine对象可以关联多个JSContext对象,并且在WebView中每次刷新操作后,此WebView的JS运行环境都是不同的JSContext对象。其作用就是用来执行JS代码,在Native和JS间进行数据的传递。


3.JSValue——JavaScript值对象


   JavaScript和Objective-C虽然都是面向对象语言,但其实现机制完全不同,OC是基于类的,JS是基于原型的,并且他们的数据类型间也存在很大的差异。因此若要在Native和JS间无障碍的进行数据的传递,就需要一个中间对象做桥接,这个对象就是JSValue。


4.JSExport


   JSExport是一个协议,Native中遵守此解析的类可以将方法和属性转换为JS的接口供JS调用。


5.一些用于C语言的结构


   你一定注意到了,上图的右下角还有一块被虚线包围的区域,其中的"类"都是C语言风格,JavaScriptCore框架是支持在Objective-C、Swift和C三种语言中使用的。


二、在Native中运行JavaScript脚本代码


   我们先来编写一个最简单的例子,使用OC代码来执行一段JS脚本。首先新建一个文件,将其后缀设置为.js,我这里将它命令为main.js,在其中编写如下代码:


(function(){

console.log("Hello Native");

})();

上面是一个自执行的函数,其中打印了“Hello Native”字符串。在Native中编写如下代码:


- (void)viewDidLoad {

   [super viewDidLoad];

   NSString * path = [[NSBundle mainBundle] pathForResource:@"main" ofType:@"js"];

   NSData * jsData = [[NSData alloc]initWithContentsOfFile:path];

   NSString * jsCode = [[NSString alloc]initWithData:jsData encoding:NSUTF8StringEncoding];

   self.jsContext = [[JSContext alloc]init];

   [self.jsContext evaluateScript:jsCode];

}

需要注意,其实这里我将创建的JSContext对象作为了当前视图控制器的属性,这样做的目的仅仅是为了方便调试,不过不对此context对象进行引用,当viewDidLoad函数执行完成后,JS运行环境也将被销毁,我们就无法在Safari中直观的看到JS代码的执行结果了。


   运行工程,记得要打开Safari浏览器的自动显示JSContent检查器,如下图:


image.png


当iOS模拟器跑起来后,Safari会自动弹出开发者工具,在控制台里面可以看到来自JavaScript的真挚问候:




刚才我们只是简单了通过原生调用了一段JS代码,但是如果Native在调JS方法时无法传参那也太low了,我们可以直接将要传递的参数格式化到字符串中,修改main.js文件如下:


function put(name){

console.log("Hello "+name);

};

put(%@);

再封装一个OC方法如下:


-(void)runJS_Hello:(NSString *)name{

   NSString * path = [[NSBundle mainBundle] pathForResource:@"main" ofType:@"js"];

   NSData * jsData = [[NSData alloc]initWithContentsOfFile:path];

   NSString * jsCode = [[NSString alloc]initWithData:jsData encoding:NSUTF8StringEncoding];

   NSString * finiString = [NSString stringWithFormat:jsCode,name];

   [self.jsContext evaluateScript:finiString];

}

在viewDidLoad中进行调用,如下:


- (void)viewDidLoad {

   [super viewDidLoad];

   self.jsContext = [[JSContext alloc]init];

   [self runJS_Hello:@"'阿凡达'"];

}

运行再看Safari控制台的结果,编程了Hello 阿凡达~:


其实evaluateScript函数执行后会将JS代码的执行结果进行返回,是JSValue类型的对象,后面会再介绍。


三、在JavaScript中调用Native方法


   有来无往非君子,同样也可以在原生中编写方法让JS来调用,示例如下:


- (void)viewDidLoad {

   [super viewDidLoad];

   void(^block)() = ^(){

       NSLog(@"Hello JavaScript");

   };

   self.jsContext = [[JSContext alloc]init];

   [self.jsContext setObject:block forKeyedSubscript:@"oc_hello"];

}

上面setObject:forKeyedSubscript:方法用来向JSContext环境的全局对象中添加属性,这里添加了一个函数属性,取名为oc_hello。这里JavaScriptCore会自动帮我们把一些数据类型进行转换,会将OC的函数转换为JS的函数,运行工程,在Safari的控制台中调用oc_hello函数,可以看到在Xcode控制台输出了对JavaScript的真挚问候,如下:

image.png



同样,如果声明的block是带参数的,JS在调用此OC方法时也需要传入参数,如果block有返回值,则在JS中也能获取到返回值,例如:


   BOOL (^block)(NSString *) = ^(NSString *name){

       NSLog(@"%@", [NSString stringWithFormat:@"Hello %@",name]);

       return YES;

   };

   self.jsContext = [[JSContext alloc]init];

   [self.jsContext setObject:block forKeyedSubscript:@"oc_hello"];

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
用手动创建新的script标签的方式,实现JavaScript脚本的异步加载
用手动创建新的script标签的方式,实现JavaScript脚本的异步加载
7 0
实用技巧:使用 jQuery 异步加载 JavaScript 脚本
  JavaScript 加载器在 Web 开发中是非常强大和有用的工具。目前流行的几个加载器,像 curljs、LABjs 和 RequireJS 使用都很广泛。他们功能强大的,但有些情况下可以有更简单的方案。
862 0
Linux USB Host-Controller的初始化代码框架分析【转】
转自:http://blog.csdn.net/zkami/article/details/2496770 usb_hcd_omap_probe (const struct hc_driver *driver) (dev/ohci/ohci-omap.
816 0
java: ant 脚本示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19...
660 0
+关注
594
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载