來由
純粹的無聊,一直在搜索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通信方式需要重新來過,架構重新設計。