前言java
動態化是移動開發技術中的重要的一部分 ,當前廣泛的動態化方案 , 如 React Native 、Weex 、Hybrid部分解決方案及以前流行的熱修復框架 JSPatch ,背後都用到了 JavaScriptCore 框架 ,由它創建起 OC 跟 JS 語言溝通的橋樑 。git
JavaScriptCore 介紹github
JavaScriptCore 是 Safari 瀏覽器 JavaScript 引擎 ,它用來解釋和執行 JavaScript 代碼 。web
JavaScriptCore 框架是一個蘋果在 iOS7 引入的框架 ,該框架讓 Objective-C 和 JavaScript 代碼直接的交互變得更加的簡單方便 ,其實就是基於 webkit 中以C/C++實現的 JavaScriptCore 的一個 OC 版本的封裝 。瀏覽器
JavaScriptCore 和 JavaScriptCore 框架是不一樣的兩個概念 ,能夠本身理解下 。框架
OC 調用 JS 代碼函數
// 直接執行js代碼 JSContext *cxt = [JSContext new]; JSValue *val = [cxt evaluateScript:@"(function ocCallJS() { return 'ocCallJS'})()"]; NSLog(@"%@",[val toString]); // ocCallJS // 註冊js方法,利用JSValue調用 JSContext *cxt = [JSContext new]; JSValue *jsFunction = [cxt evaluateScript:@" (function(arg) { return arg })"]; JSValue *val = [jsFunction callWithArguments:@[@"hello objc"]]; NSLog(@"%@",[val toString]); // hello objc
這裏有幾個對象理解下fetch
JSContext
atom
JSContext 對象表示 JavaScript 執行環境 ,全部 JavaScript 執行發生在上下文 , 全部 JavaScript 值中與上下文聯繫在一塊兒 。lua
JSValue
JSValue 實例是對 JavaScript 值的包裝 ( 引用 ) ,您可使用 JSValue 類在 JavaScript 和 Objective-C 或 Swift 表示之間轉換基本值(例如數字和字符串),以便在本機代碼和 JavaScript 代碼之間傳遞數據。您還可使用此類建立 JavaScript 對象,這些對象包含自定義類或 JavaScript 函數的本機對象,這些函數的實現由本機方法或塊提供。
JS 調用 OC 代碼
Block 方式
// 註冊一個 oc 方法給 js 調用 JSContext *cxt = [JSContext new]; cxt[@"nativeMethod"] = ^(NSString *msg) { NSLog(@"%@",msg); // jsCallOC }; // js 調用 oc 的方法 [cxt evaluateScript:@"nativeMethod('jsCallOC')"];
JSExport方式
// 定義類 暴露給 js @protocol JSBridgeObjProtocol <JSExport> - (NSString *)fetchArticleContent; @end @interface JSBridgeObj : NSObject<JSBridgeObjProtocol> @property (nonatomic, copy) NSString *articleTitle; - (NSString *)fetchArticleContent; @end @implementation JSBridgeObj - (NSString *)fetchArticleContent { return @"js call oc"; } @end // js 調用 oc 方法 JSContext *cxt = [JSContext new]; cxt[@"jsBridge"] = [JSBridgeObj new]; JSValue *val = [cxt evaluateScript:@"jsBridge.fetchArticleContent()"]; NSLog(@"%@",[val toString]); // js call oc
JXExport 實現的協議將 OC 類及其實例方法,類方法和屬性導出到 JavaScript 代碼
這樣基於 JSContext 咱們能夠完成兩種語言間通訊
Hybrid 中的應用
APP 混合開發中 ,在 UIWebView 中獲取 JSContext 對象 ,該操做借用了蘋果的私有方法 。
// 獲取當前 WebView 的 JS 上下文 JSContext *context=[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
不過該方法獲取 JS 上下文有幾個問題:
1 ) 獲取 JS 上下文的時機不肯定 ,好比建立 UIWebView 對象 ,UIWebView 不一樣代理回調方法中獲取到 JS 上下文都是不同的 ,並且每次加載一個新的 URL 時 , 都會廢棄舊的 JS 上下文 ,建立新的 JS 上下文 。
所以獲取 JS 上下文的時間點很重要 ,也就是在剛剛建立好新的 JS 上下文那一刻 。
只不過蘋果並無在 iOS 的 SDK 中暴露出來 ,而 macOS 的 SDK 中有獲取建立好的 JS 上下文的代理方法。
webView:didCreateJavaScriptContext:forFrame:
在 GitHub 上有這樣一個項目 TS_JavaScriptContext 能夠拿到了 JS 上下文建立的事件 ,只不過也是改獲取方法也是蘋果的私有 API , 原來項目中使用了這個庫上架蘋果應用商店沒有問題 ,如今審覈狀況不太瞭解 。
2 ) WKWebView 目前我尚未找到獲取 JS 上下文的方法
在 UIWebView 中獲取 JS 上下文的方法在 WKWebView 中是不起做用的 。
WKWebView 不支持 JavaScriptCore 的方式, 但提供 messagehandler 的方式爲 JS 與 OC 通訊 。關於 WKWebView 相關知識 ,後續再聊 。
歡迎關注公衆號:dreamlee,你的成長咱們一塊兒見證!