前段時間作app活動,發現與JS交互方面有些混亂,爲了梳理交互操做,又從新看了一遍原生與JS交互方面的東西javascript
同時找到了下面參考文檔中的深刻淺出和全面解析寫的還不錯,多餘的就不贅述了,本身總結一下,不想看的看官門能夠跳過【我的總結】這一部分html
首先要聲明獲取JSContext對象,有下面三個方式,三選一java
- (void)webViewDidFinishLoad:(UIWebView *)webView { // 1.這種方式須要傳入一個JSVirtualMachine對象,若是傳nil,會致使應用崩潰的。 JSVirtualMachine *JSVM = [[JSVirtualMachine alloc] init]; JSContext *JSCtx = [[JSContext alloc] initWithVirtualMachine:JSVM]; // 2.這種方式,內部會自動建立一個JSVirtualMachine對象,能夠經過 JSCtx.virtualMachine // 看其是否建立了一個JSVirtualMachine對象。 JSContext *JSCtx = [[JSContext alloc] init]; // 3. 經過webView的獲取JSContext。 JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; }
JSContext對象對應一個全局對象(global object)。例如web瀏覽器中的JSContext,起全局對象就是window對象。全局變量是全局對象的屬性,能夠經過JSValue對象或者context下標的方式來訪問。ios
因此感受用方法3,去獲取而不是建立更好一些。web
JavaScript 與 Objective-C 交互主要經過2種方式:瀏覽器
block方式:使用block將響應方法暴露給JavaScript,從而完成Objective-C的一些操做markdown
JSExport 協議:經過繼承JSExport協議的方式來導出指定的方法和屬性,能夠將OC的中某個對象直接暴露給JS使用,並且在JS中使用就像調用JS的對象同樣天然。併發
OC變量 <---> JS變量app
//執行的JS操做 爲a賦值 JSValue *value = [context evaluateScript:@"var a = 1+2*3;"]; //獲取a的值的三種方法 NSLog(@"a = %@", [context objectForKeyedSubscript:@"a"]);//經過context的實力方法objectForKeyedSubscript NSLog(@"a = %@", [context.globalObject objectForKeyedSubscript:@"a"]);//經過context.globalObject的ObjectForKeyedSubscript實例方法 NSLog(@"a = %@", context[@"a"]); //經過下標 //輸出結果Output: a = 7 a = 7 a = 7
JS方法 ---> OC方法 async
JS方法
//點擊調用shareClick方法 <input type="button" value="分享" onclick="shareClick()" /> //shareClick方法 function shareClick() { //調用原生share方法 //調用方法不帶參數 share(); //調用方法帶參數 share('測試分享的標題','測試分享的內容','url=http://www.baidu.com'); }
OC方法
- (void)addShareWithContext:(JSContext *)context { context[@"share"] = ^() { //從JavaScript代碼傳過來的參數 NSArray *args = [JSContext currentArguments]; //參數的一些處理 if (args.count < 3) { return ; } NSString *title = [args[0] toString]; NSString *content = [args[1] toString]; NSString *url = [args[2] toString];
// 在這裏執行分享的操做
}; }
OC方法 ---> JS方法
JS代碼
function shareResult(channel_id,share_channel,share_url) { //拼接數據 var content = channel_id+","+share_channel+","+share_url; asyncAlert(content); //修改當前returnValue的值 document.getElementById("returnValue").value = content; }
OC代碼
- (void)addShareWithContext:(JSContext *)context { context[@"share"] = ^() { NSArray *args = [JSContext currentArguments]; if (args.count < 3) { return ; } NSString *title = [args[0] toString]; NSString *content = [args[1] toString]; NSString *url = [args[2] toString]; // 在這裏執行分享的操做 // 將分享結果返回給js NSString *jsStr = [NSString stringWithFormat:@"shareResult('%@','%@','%@')",title,content,url]; [[JSContext currentContext] evaluateScript:jsStr]; }; }
這樣的話也完成了JS的回調,既調用JS中的方法處理返回值
簡單的說就是寫一個繼承JSExport的協議,寫一個類遵循該協議,將這個類做爲一個變量交給JavaScriptCore。這樣JavaScriptCore會自動認定繼承JSExport這個類的協議爲要導入到JavaScript的方法和屬性列表,從而進行導入。
代碼1顯示了協議中的變量,方法和類方法。代碼2顯示了對應的JavaScript中調用的方法
代碼1
@protocol MyPointExports <JSExport> //對於每一個導出的Objective-C屬性,JavaScriptCore都會在原型上建立JavaScript訪問器屬性。 @property double x; @property double y; //對於每一個導出的實例方法,JavaScriptCore都會建立一個相應的JavaScript函數做爲原型對象的屬性。 - (NSString *)description; - (instancetype)initWithX:(double)x y:(double)y; //對於每一個導出的類方法,JavaScriptCore在構造函數對象上建立一個JavaScript函數 + (MyPoint *)makePointWithX:(double)x y:(double)y; @end
代碼2
// Objective-C properties become fields. point.x; point.x = 10; // Objective-C instance methods become functions. point.description(); // Objective-C initializers can be called with constructor syntax. var p = MyPoint(1, 2); // Objective-C class methods become functions on the constructor object. var q = MyPoint.makePointWithXY(0, 0);
其中MyPoint爲遵循MyPointExports的類
你可能注意到了,後兩個方法參數寫法上彷佛有些變化。
如上面英文提到的,初始化方法能夠用構造函數方法調用
而多參數問題,導入到JavaScript時由這麼一個規則
例如:OC中爲 doFoo:withBar:
JavaScript中爲 doFooWithBar
很差記? 蘋果又貼心的給了一個宏來指定導出到Javascript的方法名
@protocol MyClassJavaScriptMethods <JSExport> JSExportAs(doFoo, - (void)doFoo:(id)foo withBar:(id)bar ); @end
到此,用法方面就結束了
其實若是你看了下面的參考文檔,你就會以爲他們確實寫的很全面,我再寫這一篇的時候也這麼以爲,一樣也猶豫過,在很顯然不如別人寫的好的狀況下要不要在寫下去。
後來想清了一個問題,雖然說不要重複造輪子,可是不會造輪子的話,永遠只能當組裝師搬運工,學會造輪子以後才能成爲創造者。一千個讀者就有一千個哈姆雷特,或許你的切入點、視角更好呢,就算不是完美,至少你走過了這一步,也印象更深入了些。雖然不完美,但仍是寫完了,但願可以對你有所幫助。
PS:若是你看了官方文檔,會發現,大多數信息源仍是官方文檔~~~