判断js引擎是javascriptCore或者v8
来由
纯粹的无聊,一直在搜索JavaScriptCore和SpiderMonkey的一些信息,却无意中学习了如何在ios的UIWebView中判断其js解析引擎的方法:
if (window.devicePixelRatio) { //If WebKit browser
var st = escape(navigator.javaEnabled.toString());
if (st === 'function%20javaEnabled%28%29%20%7B%20%5Bnative%20code%5D%20%7D') {
document.write('V8 detected');
} else {
document.write('JSC detected');
}
} else {
document.write("Not a WebKit browser");
}
只需上述一串代码,在ios中自然是JavaScriptCore的内核,在安卓下是v8引擎。
在之前的文章objC与js通信实现--WebViewJavascriptBridge中,讲述了cordova的桥接机制-通过UIWebView的stringbyEvaluateJavascriptString方法通信,但是通过这个借口,虽然我们可以采用内置的jsc引擎执行js代码,但是无法进行更细粒度,深入到javascript运行时来执行代码,最直接的表现就是“无法在oc端对执行的js进行错误控制,如异常处理机制”。通过额外引入或链接javascriptCore,可以在c层次与iOS进行通信,效率提高很大。
对比
1,在iOS中通过UIWebView组件的stringByEvaluateJavascriptString:(NSString *)方法来调用。但是这种方式有几个弊端:
1)oc调用js有返回值,属于同步调用;而js调用oc是通过创建iframe并设置src,oc端的UIWebVIew拦截请求,然后再通过stringByEvaluateJavascriptString执行js端的方法,获取js的参数(序列化的json字符串),在oc端进行反序列化,最后调用oc的函数;
2)oc端的stringByEvaluateJavascriptString在执行js代码时会阻塞js端代码的执行;
3)通过1)的流程可看出,通过UIWebView实现的bridge机制性能堪忧,交互蛋疼;
4)通过UIWebView执行js代码段,有几点限制:由于ios并未给予我们通过UIWebView访问javascript运行时的权限,因此即使通过stringByEvaluateJavascriptString执行错误的js代码,我们在oc端仍无法获取错误消息,更无从谈起回调函数;不过,这种方式的好处就是没有涉及到内存管理。
2,目前有三种方案实现oc与js通信,第一种继续使用cordova的通信机制,也就是目前比较流行的UIWebView;第二种采用React Native的通信机制,使用iOS7内置的javascriptCore引擎并在js,oc两层搭建桥接层,并且每层持有2份相同的配置表,每个表中都记录js,oc透出的API,并结合iOS的事件机制完成oc和js的互调;第三种则仍是采用iOS7内置的javascriptCore框架,不同于React Native的是使用jsc提供的通信机制,这套机制类似于android下WebView编码方式,oc端只需实现JSExpose协议,就将实现该协议的对象透到当前的上下文中,如在UIWebView控件中就为改webview对应的上下文,即使h5页面切换,上下文仍是不变,可以理解为一个单例。
3, 综上三种方案,第一种代价最低,而且流程比较完善,而且已经系统化,但是性能是硬伤;第二种则是非常好的借鉴,RN的方式不仅仅适用于javascriptCore,而且也适用于其他引擎如SpiderMonkey,但是如果要采用RN的方案可能需要更多时间来搞清楚具体的实现细节和技巧,难度略大;第三种则是比较而言比较无害而且实现难度并不算大的方案,目前尚妆iOS下只适配iOS7以上的设备,因此我们不需要针对iOS6及以下设备做兼容(引入第三方的javascriptCore),而且通过使用内置的js引擎和oc进行通信,在c/c++层面的效率将会大大提高(相比较UIWebview而言),缺点则是可能目前采用的bridge通信方式需要重新来过,架构重新设计。