JavaScriptCore (一)

来源:互联网 发布:淘宝网飞机票里程 编辑:程序博客网 时间:2024/04/29 04:36

 JavaScriptCore  什么是JavaScriptCore


(一)JavaScriptCore 是一个提供网页Javascript引擎接口的的框架。框架提供了强大的功能,可以实现Swift/Objective-C 和 Javascript 代码之间的交互。(React Native 技术 就是对JavaScriptCore 强大功能的一个实际运用。)

(二)JavaScriptCore是线程安全的,它里头有几个核心组件:JSVirtualMachine,JSContext, JSValue


JSVirtualMachine

1. JSVirtualMachine(虚拟机制类)  :JavaScript代码其实是在JSVirtualMachine类提供的环境中执行,通常不必直接对它进行操作,除非需要进行并发执行JavaScript,因为一个JSVirtualMachine是不能再同一时间执行多线程任务的,所以此时需要使用多个虚拟机制。

2. 每一个JSVirtualMachine实例都与自己的堆栈和垃圾回收机制,所以不能再不同的虚拟机制之间传递对象信息,因为虚拟机制的垃圾回收器不知道怎样处理来至其它堆栈的值。需要使用到它有两个主要情况:为了并发执行JavaScript;JavaScript 和 Objecive-C/Swift 之间桥接对象的内存管理(注意使用JSManagedValue)。


JSContext

1. JSContext OC支持 JavaScript执行的环境对象,是运行 JavaScript代码的环境。OC语言 JavaScript之间的桥接,可以依赖它来实现。一个 JSContext是一个全局环境的实例,每一个JavaScript context都隶属于一个虚拟机。同虚拟机制类不同,不同context之间是可以进行对象信息传递的(一个虚拟机可以内含多个context,只要将它们放置在同一个虚拟机制下)

       2. JSContext 通常与UIWebView一起使用,那应该怎样得到webview中加载的javascript代码呢,不再通过URL拦截,使用JSContext的方法直接取 UIWebView context,然后进行对JS操作:context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

       3. 当然也可以使(evaluateScript:)方法添加Javascript代码到context中,或者执行javascript代码。


JSValue

1. JSValue JavaScript值的一个引用实例对象,它可以代表任何JavaScript值类型,一个JSValue实例是搬到在它所依赖的JSContext中的,任何来至这个context中的值都会是一个JSValue类型。

         a)可实现 OC|Swift JavaScript中基本数据类型的转换,并能够实现原生和JavaScript之间的数据传递,

         b)可以创建JavaScript对象,通过原生的方法或者blocks提供其中的JavaScript函数实现。

2. evaluateScript: 执行javascript代码,返回值JSValue


        

(三)下面直接上代码,演示一下如何使用JavaScriptCore框架来实现 Javascript 到 native的调用过程。



        /// context中添加 javascript代码

        JSContext *context = [[JSContextalloc] init];

        [context evaluateScript:@"var num = 5 + 5"];

        [context evaluateScript:@"var names = ['Grace', 'Ada', 'Margaret']"];

        [context evaluateScript:@"var triple = function(value) { return value * 3 }"];

        [context evaluateScript:@"var sendValueToNative = ({'name1':'1','value1':'a','name2':'2','value2':'b' })"];



        /// 利用 context执行 javascript代码

        JSValue *tripleNum = [contextevaluateScript:@"triple(num)"];

        NSLog(@"Tripled: %d", [tripleNumtoInt32]);

        // Tripled: 30

        JSValue *value1 = [contextevaluateScript:@"sendValueToNative"];

        NSLog(@"value1 = %@",[value1toDictionary]);

        //value1 = {name1 = 1; name2 = 2;  value1 = a; value2 = b;}



        /*

         JSContext JSValue实例使用下标的方式我们可以很容易地访问我们之前创建的 context的任何值。JSContext需要一个字符串下标,而 JSValue允许使用字符串或整数标来得到里面的对象和数组:

         */

        JSValue *names = context[@"names"];

        JSValue *initialName = names[0];

        NSLog(@"The first name: %@", [initialNametoString]);

        // The first name: Grace



        /*

         JSContext 还有另外一个有用的招数:通过设置上下文的 exceptionHandler属性,你可以观察和记录语法,类型以及运行时错误。 exceptionHandler是一个接收一个 JSContext引用和异常本身的回调处理:

         */

        context.exceptionHandler = ^(JSContext *context,JSValue *exception) {

            NSLog(@"JS Error: %@", exception);

        };

        [context evaluateScript:@"function multiply(value1, value2) { return value1 * value2 "];

        // JS Error: SyntaxError: Unexpected end of script





        /*

         1. 现在我们知道了如何从 JavaScript环境中提取值以及如何调用其中定义的函数。那么反向呢?我们怎样才能从 JavaScript访问我们在 Objective-C Swift定义的对象和方法?

         2. JSContext访问我们的本地客户端代码的方式主要有两种:block JSExport协议。

         3. 当一个 Objective-C block被赋给 JSContext里的一个标识符,JavaScriptCore会自动的把 block封装在 JavaScript函数里。这使得在 JavaScript中可以简单的使用 Foundation Cocoa类,所有的桥接都为你做好了。

         4. 由于 block可以保有变量引用,而且 JSContext也强引用它所有的变量,为了避免强引用循环需要特别小心。避免保有你的 JSContext或一个 block里的任何 JSValue。相反,使用 [JSContext currentContext]得到当前上下文,并把你需要的任何值用参数传递。

         */

        context[@"simplifyString"] = ^(NSString *input) {

            NSMutableString *mutableString = [inputmutableCopy];

            CFStringTransform((__bridgeCFMutableStringRef)mutableString,NULL, kCFStringTransformToLatin, NO);

            CFStringTransform((__bridgeCFMutableStringRef)mutableString,NULL, kCFStringTransformStripCombiningMarks,NO);

            return mutableString;

        };

        NSLog(@"%@", [contextevaluateScript:@"simplifyString('안녕하새요!')"]);


        context[@"sendValue"] =

        ^(NSDictionary *objc)

        {

            return objc[@"name1"];

        };

        JSValue *value2 =  [contextevaluateScript:@"sendValue({'name1':'one','value1':'a','name2':'2','value2':'b' })"];

        NSLog(@"value2 = %@",[value2toString]);

        // value2 = one




        //注册一个匿名函数

        JSValue *jsFunction = [contextevaluateScript:@" (function(string) { return 'hello objc '+ string })"];

        //调用

        JSValue *value3 = [jsFunctioncallWithArguments:@[@"coding is beauty"]];

        NSLog(@"value3 = %@",[value3toString]);

        //value3 = hello objc coding is beauty


        // 再注册执行一个有名函数,并调用callWithArguments这个方法进行参数传值。(JS里面函数也是对象)

        [context evaluateScript:@"function addfun(a,b) {return a+b}"];

        JSValue *n = [context[@"addfun"]callWithArguments:@[@2, @3]];

        NSLog(@"---%@", @([ntoInt32]));//---5






(四)补充。

1. Javascript 的跨平台性非常好,因此所讨论的技术其实就是如何实现Native与Javascript之间的通讯。这样做的使用示例最直接的就是实现一个WebView 和 native 的交互。JavaScriptCore就是为之而设计。

2. UIWebView 中有提供了几个代理方法,利用其中的URL拦截或者js注入等可以实现一些简单的网页到native原生的交互。

3. 罗列几篇参考文章,

//http://nshipster.cn/javascriptcore/

//https://www.raywenderlich.com/124075/javascriptcore-tutorial

//http://www.jianshu.com/p/a329cd4a67ee



0 0
原创粉丝点击