Hybrid 载体的变化(二)

阿羊羊

阿羊羊

发表于 2017-06-05 09:10:12

引擎的变化让你的JavaScript执行速度更快,并且让你的交互能力变的更为强大,iOS平台从iOS7开始提供了JavaScriptCore框架,Android平台的v8就更不用说了,至今延伸出来的包括有Node.js这种明星项目,正因为独立JS引擎让人们在追求Hybrid极致的情况下找到了Web和Native新的平衡点,比如Weex,React Native这样的移动解决方案,今天我们就要谈一谈iOS上JS的载体引擎“JavaScriptCore”,有兴趣的朋友直接阅读: https://developer.apple.com/reference/javascriptcore  ,当然你也可以接着往下阅读。

额外提一句,如果没有特殊情况,所有的例子都是Swift3.1版本。

JavaScriptCore是iOS平台上提供的JavaScript虚拟机,为JavaScript的执行提供了底层资源,这是用C++编写,并且用Objective-c/Swift包装之后提供给iOS开发者使用的框架。从这里我们可以知道,JavaScriptCore至少包含:Lexer,Parser,LLInt,JIT等,理论上对于JavaScript开发者来说不懂这些不要紧,了解一下即可。Objective-C和Swift提供的JavaScriptCore稍许有一些不同,这些只是使用方式上的不同,理论上你需要看的就只是.h文件中的几个。

#ifndef JavaScriptCore_h
#define JavaScriptCore_h

#include <JavaScriptCore/JavaScript.h>
#include <JavaScriptCore/JSStringRefCF.h>

#if defined(__OBJC__) && JSC_OBJC_API_ENABLED

#import "JSContext.h"
#import "JSValue.h"
#import "JSManagedValue.h"
#import "JSVirtualMachine.h"
#import "JSExport.h"

#endif
#endif /* JavaScriptCore_h */
import JavaScriptCore.JSBase
import JavaScriptCore.JSContext
import JavaScriptCore.JSContextRef
import JavaScriptCore.JSExport
import JavaScriptCore.JSManagedValue
import JavaScriptCore.JSObjectRef
import JavaScriptCore.JSStringRef
import JavaScriptCore.JSStringRefCF
import JavaScriptCore.JSTypedArray
import JavaScriptCore.JSValue
import JavaScriptCore.JSValueRef
import JavaScriptCore.JSVirtualMachine
import JavaScriptCore.JavaScript
import JavaScriptCore.WebKitAvailability

正常情况下一个JSContext代表了一个JavaScript执行环境,如果你愿意也可以通过JSVirtualMachine来提供完整的执行环境,它们之间是有不同的,一个JSVirtualMachine可以包含多个JSContext,当然你的JSContext肯定不运行包含JSVirtualMachine了,如果你要手动管理JavaScript和Native桥接对象的内存,还是需要使用这个虚拟机的,正常情况下JSVirtualMachine不应该手动去初始化它,而是要用JSContext,系统会为你分配一个JSVirtualMachine。

let jsc = JSContext()
let num = jsc?.evaluateScript("1 + 2")

使用JSContext去执行JS中定义的计算或者值,这都可以得到完整的转换,上述的一个例子只是说明了,Native如何调用JS的方式,使用"evaluateScript"直接执行任何的JS代码即可,而且如果有返回值,都可以无缝的转换成Native的对象,你可以使用print打印一下num试试效果,当然它会是一个Optional类型。

let jsc = JSContext()
jsc?.exceptionHandler = {
     (context, exception) in
     print("(String(describing: exception))")
};
let num = jsc?.evaluateScript("1 + 2")
print("(String(describing: num!))")
jsc?.evaluateScript("var tips = function(){ return 100}")
let val_number = jsc?.globalObject.invokeMethod("tips", withArguments: [])
print("(val_number?.toNumber())")

如果想要让JS主动的调用并且向Native传输数据,也非常简单,如下:

jsc[@"callNative"] = ^(JSValue *instance, JSValue *tasks, JSValue *callback){     
    NSString *instanceId = [instance toString];     
    NSArray *tasksArray = [tasks toArray];     
    NSString *callbackId = [callback toString];
};
let logger = {
   (log: String) -> Int in
            
   return 1
};
jsc?.setObject(logger , forKeyedSubscript: "logger" as NSCopying & NSObjectProtocol)

当然在一个global环境中,以及任何Object或者Function里,有了JSValue都可以直接使用“call”或者“invokeMthod”方法来直接调用,比如:

val?.call(withArguments: ["12345"])
jsc?.globalObject.invokeMethod("logger", withArguments: ["1234567"])

当我们有了这些强大的能力后,从Native To JavaScript交互的地方都可以设计的比较完美一些,我们可以用JSExport协议来设计一个模块式的交互,对于整体项目的维护,扩展都有很大的帮助,这也是为什么说,当我们Hybrid的载体变化之后,对于这些交互,在某种程度上来说,有了质的提升。

@objc protocol JSDelegate:JSExport {    
    func callNativeModelExe(obj:JSValue) -> Int
}
@objc class JSModelExe: NSObject,JSDelegate {    
    func callNativeModelExe(obj: JSValue) -> Int {        
        let num = obj.toNumber();        
        print("(String(describing: num))");        
        return 1;
    }
}

你身边如果有朋友对混合领域(跨技术栈)或全栈,编程感悟感兴趣,可以转发给他们看哦,^_^先谢过啦。

更多精彩内容可关注我的个人微信公众号:搜索fed-talk或者扫描下列二维码,也欢迎您将它分享给自己的朋友。

iOS赞赏没啦,估计以后也只能用这种形式了:

相关帖子
用户评论
开源开发学习小组列表