亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

iOS開發日記28-OC與JS的交互(JavaScriptCore)

2019-11-14 18:13:53
字體:
來源:轉載
供稿:網友

今天博主有一個OC與JS的交互的需求,遇到了一些困難點,在此和大家分享,希望能夠共同進步.

上一篇博文與大家分享了如何使用webview與JS進行交互,但是隨著新的API的開放,我們不僅僅需要在webview中與JS進行交互,也需要在很多其他的框架中與JS進行交互,有兩種方法提供給大家:

1.蘋果在7.0之后新開放得API javaScriptCore框架,讓我們能夠更簡便的使用OC與JS進行交互.

2.使用第三方框架WebViewJavascriptBridge

今天就和大家總結一下JavaScriptCore框架的使用.

JavaScriptCore中的類

在項目中引入JavaScriptCore后,鏈到頭文件中,除了大段的Copyright注釋可以看到里面只要引入了5個文件,每個文件里都定義跟文件名對應的類:

  • JSContext
  • JSValue
  • JSManagedValue
  • JSVirtualMachine
  • JSExport

JavaScriptCore_Head

雖說代碼中的注釋介紹的也比較詳細了,但是如同一圖頂萬言,對程序員來說代碼更有說服力。本文就先來說說這些類相對比較好理解但又很常用的JSContext和JSValue以及它們方法的使用方式和效果。

JSContext和JSValue

JSVirtualMachine為JavaScript的運行提供了底層資源,JSContext就為其提供著運行環境,通過- (JSValue *)evaluateScript:(NSString *)script;方法就可以執行一段JavaScript腳本,并且如果其中有方法、變量等信息都會被存儲在其中以便在需要的時候使用。而JSContext的創建都是基于JSVirtualMachine- (id)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine;,如果是使用- (id)init;進行初始化,那么在其內部會自動創建一個新的JSVirtualMachine對象然后調用前邊的初始化方法。

JSValue則可以說是JavaScript和Object-C之間互換的橋梁,它提供了多種方法可以方便地把JavaScript數據類型轉換成Objective-C,或者是轉換過去。其一一對應方式可見下表:

 
 
Objective-CJavaScriptJSValue ConvertJSValue Constructor
nilundefined valueWithUndefinedInContext
NSNullnull valueWithNullInContext:
NSStringstringtoString 
NSNumbernumber, booleantoNumber
toBool
toDouble
toInt32
toUInt32
valueWithBool:inContext:
valueWithDouble:inContext:
valueWithInt32:inContext:
valueWithUInt32:inContext:
NSDictionaryObject objecttoDictionaryvalueWithNewObjectInContext:
NSArrayArray objecttoArrayvalueWithNewArrayInContext:
NSDateDate objecttoDate 
NSBlockFunction object  
idWrapper objecttoObject
toObjectOfClass:
valueWithObject:inContext:
ClassConstructor object  

 

基本類型轉換

先看個簡單的例子:

復制代碼
1     JSContext *context = [[JSContext alloc] init];2     JSValue *jsVal = [context evaluateScript:@"21+7"];3     int iVal = [jsVal toInt32];4     NSLog(@"JSValue: %@, int: %d", jsVal, iVal);5      6     //Output:7     // JSValue: 28, int: 28
復制代碼

很簡單吧,還可以存一個JavaScript變量在JSContext中,然后通過下標來獲取出來。而對于Array或者Object類型,JSValue也可以通過下標直接取值和賦值。

復制代碼
 1     JSContext *context = [[JSContext alloc] init]; 2     [context evaluateScript:@"var arr = [21, 7 , 'iderzheng.com'];"]; 3     JSValue *jsArr = context[@"arr"]; // Get array from JSContext 4       5     NSLog(@"JS Array: %@; Length: %@", jsArr, jsArr[@"length"]); 6     jsArr[1] = @"blog"; // Use JSValue as array 7     jsArr[7] = @7; 8       9     NSLog(@"JS Array: %@; Length: %d", jsArr, [jsArr[@"length"] toInt32]);10      11     NSArray *nsArr = [jsArr toArray];12     NSLog(@"NSArray: %@", nsArr);13      14     //Output:15     // JS Array: 21,7,iderzheng.com Length: 316     // JS Array: 21,blog,iderzheng.com,,,,,7 Length: 817     // NSArray: (18     // 21,19     // blog,20     // "iderzheng.com",21     // "<null>",22     // "<null>",23     // "<null>",24     // "<null>",25     // 726     // )
復制代碼

通過輸出結果很容易看出代碼成功把數據從Objective-C賦到了JavaScript數組上,而且JSValue是遵循JavaScript的數組特性:無下標越位,自動延展數組大小。并且通過JSValue還可以獲取JavaScript對象上的屬性,比如例子中通過"length"就獲取到了JavaScript數組的長度。在轉成NSArray的時候,所有的信息也都正確轉換了過去。

方法的轉換

各種數據類型可以轉換,Objective-C的Block也可以傳入JSContext中當做JavaScript的方法使用。比如在前端開發中常用的log方法,雖然JavaScritpCore沒有自帶(畢竟不是在網頁上運行的,自然不會有window、document、console這些類了),仍然可以定義一個Block方法來調用NSLog來模擬:

復制代碼
 1     JSContext *context = [[JSContext alloc] init]; 2     context[@"log"] = ^() { 3     NSLog(@"+++++++Begin Log+++++++"); 4       5     NSArray *args = [JSContext currentArguments]; 6     for (JSValue *jsVal in args) { 7     NSLog(@"%@", jsVal); 8     } 9      10     JSValue *this = [JSContext currentThis];11     NSLog(@"this: %@",this);12     NSLog(@"-------End Log-------");13     };14      15     [context evaluateScript:@"log('ider', [7, 21], { hello:'world', js:100 });"];16      17     //Output:18     // +++++++Begin Log+++++++19     // ider20     // 7,2121     // [object Object]22     // this: [object GlobalObject]23     // -------End Log-------
復制代碼

通過Block成功的在JavaScript調用方法回到了Objective-C,而且依然遵循JavaScript方法的各種特點,比如方法參數不固定。也因為這樣,JSContext提供了類方法來獲取參數列表(+ (JSContext *)currentContext;)和當前調用該方法的對象(+ (JSValue *)currentThis)。對于"this",輸出的內容是GlobalObject,這也是JSContext對象方法- (JSValue *)globalObject;所返回的內容。因為我們知道在JavaScript里,所有全局變量和方法其實都是一個全局變量的屬性,在瀏覽器中是window,在JavaScriptCore是什么就不得而知了。

Block可以傳入JSContext作方法,但是JSValue沒有toBlock方法來把JavaScript方法變成Block在Objetive-C中使用。畢竟Block的參數個數和類型已經返回類型都是固定的。雖然不能把方法提取出來,但是JSValue提供了- (JSValue *)callWithArguments:(NSArray *)arguments;方法可以反過來將參數傳進去來調用方法。

復制代碼
 1     JSContext *context = [[JSContext alloc] init]; 2     [context evaluateScript:@"function add(a, b) { return a + b; }"]; 3     JSValue *add = context[@"add"]; 4     NSLog(@"Func: %@", add); 5       6     JSValue *sum = [add callWithArguments:@[@(7), @(21)]]; 7     NSLog(@"Sum: %d",[sum toInt32]); 8     //OutPut: 9     // Func: function add(a, b) { return a + b; }10     // Sum: 28
復制代碼

JSValue還提供- (JSValue *)invokeMethod:(NSString *)method withArguments:(NSArray *)arguments;讓我們可以直接簡單地調用對象上的方法。只是如果定義的方法是全局函數,那么很顯然應該在JSContextglobalObject對象上調用該方法;如果是某JavaScript對象上的方法,就應該用相應的JSValue對象調用.

 

下面貼上代碼,我們還是以webview作為示例,各位看官自行深究.

首先我們添加協議

 @interface ViewController ()<UIWebViewDelegate>  

實現代理方法

#PRagma mark --webViewDelegate  

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType  

{  

    //網頁加載之前會調用此方法  

    //retrun YES 表示正常加載網頁 返回NO 將停止網頁加載  

return YES;  

}  

-(void)webViewDidStartLoad:(UIWebView *)webView  

{  

    //開始加載網頁調用此方法  

}  

-(void)webViewDidFinishLoad:(UIWebView *)webView  

{  

       //網頁加載完成調用此方法  

}  

-(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error  

{  

     //網頁加載失敗 調用此方法  

}  

每個方法是什么時候調用都在注釋里面

1.我們先嘗試用oc調用一下js方法

 -(void)webViewDidFinishLoad:(UIWebView *)webView  

{  

      //網頁加載完成調用此方法  

      //首先創建JSContext 對象(此處通過當前webView的鍵獲取到jscontext)  

      JSContext *context=[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];  

      NSString *alertJS=@"alert('test js OC')"; //準備執行的js代碼  

      [context evaluateScript:alertJS];//通過oc方法調用js的alert

}

2.下來我們使用js調用iOS

js調用iOS分兩種情況

一,js里面直接調用方法

二,js里面通過對象調用方法

 

首先我們看第一種,直接調用方法。

其中用到了iOS的block

 -(void)webViewDidFinishLoad:(UIWebView *)webView  

{  

      //網頁加載完成調用此方法  

      //iOS調用js  

      //首先創建JSContext 對象(此處通過當前webView的鍵獲取到jscontext)  

      JSContext *context=[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];  

      //js調用iOS  

      //第一種情況  

      //其中test1就是js的方法名稱,賦給是一個block 里面是iOS代碼  

      //此方法最終將打印出所有接收到的參數,js參數是不固定的 我們測試一下就知道  

      context[@"test1"] = ^() {  

      NSArray *args = [JSContext currentArguments];   

      for (id obj in args) {  

            NSLog(@"%@",obj);  

        }  

    };  

    //此處我們沒有寫后臺(但是前面我們已經知道iOS是可以調用js的,我們模擬一下)  

    //首先準備一下js代碼,來調用js的函數test1 然后執行  

    //一個參數  

    NSString *jsFunctStr=@"test1('參數1')";  

    [context evaluateScript:jsFunctStr];  

    //二個參數  

    NSString *jsFunctStr1=@"test1('參數a','參數b')";  

    [context evaluateScript:jsFunctStr1];  

}  

以上代碼中 給test1賦值的block要是執行了那么結果就是對的,js調用了iOS

我們看結果

 

我們看到參數被打印出來了,而且一個參數和兩個參數都可以,也符合js參數個數不限制

 

下來我們看第二種情況 就是js 中是通過一個對象來調用方法的。

此處稍微復雜一點我們需要使用到

JSExport

凡事添加了JSExport協議的協議,所規定的方法,變量等 就會對js開放,我們可以通過js調用到

此處有點繞。我們直接看代碼

首先創建一個類 繼承NSObject 并且規定一個協議

   #import <Foundation/Foundation.h>  

   #import <JavaScriptCore/JavaScriptCore.h>   

   //首先創建一個實現了JSExport協議的協議  

   @protocol TestJSObjectProtocol <JSExport>  

   //此處我們測試幾種參數的情況  

-(void)TestNOParameter;  

-(void)TestOneParameter:(NSString *)message;  

-(void)TestTowParameter:(NSString *)message1 SecondParameter:(NSString *)message2;  

@end  

//讓我們創建的類實現上邊的協議  

@interface TestJSObject : NSObject<TestJSObjectProtocol>  

@end

 

類的實現

    #import "TestJSObject.h"    

    @implementation TestJSObject  

     //一下方法都是只是打了個log 等會看log 以及參數能對上就說明js調用了此處的iOS 原生方法  

-(void)TestNOParameter  

{  

    NSLog(@"this is ios TestNOParameter");  

}  

-(void)TestOneParameter:(NSString *)message  

{  

    NSLog(@"this is ios TestOneParameter=%@",message);  

}  

-(void)TestTowParameter:(NSString *)message1 SecondParameter:(NSString *)message2  

{  

   NSLog(@"this is ios TestTowParameter=%@  Second=%@",message1,message2);  

}  

@end

 

下面我們在weibview加載完成之后調用測試一下

-(void)webViewDidFinishLoad:(UIWebView *)webView  

{  

      //網頁加載完成調用此方法  

      //首先創建JSContext 對象(此處通過當前webView的鍵獲取到jscontext)  

      JSContext *context=[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];  

      //第二種情況,js是通過對象調用的,我們假設js里面有一個對象 testobject 在調用方法  

      //首先創建我們新建類的對象,將他賦值給js的對象  

      TestJSObject *testJO=[TestJSObject new];  

      context[@"testobject"]=testJO;  

      //同樣我們也用剛才的方式模擬一下js調用方法  

      NSString *jsStr1=@"testobject.TestNOParameter()";  

      [context evaluateScript:jsStr1];  

      NSString *jsStr2=@"testobject.TestOneParameter('參數1')";  

      [context evaluateScript:jsStr2];  

      NSString *jsStr3=@"testobject.TestTowParameterSecondParameter('參數A','參數B')";  

      [context evaluateScript:jsStr3];  

}  

結果如下:

TestJSOC[7038:258939] this is ios TestNOParameter

TestJSOC[7038:258939] this is ios TestOneParameter=參數1

TestJSOC[7038:258939] this is ios TestTwoParameter=參數A Second=參數B

好了 我們看到了結果 三個方法都調用了 

ok兩種方式都完成了

http://nshipster.cn/javascriptcore/

http://www.webryan.net/2013/10/about-ios7-javascriptcore-framework/


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲香蕉成视频在线观看| 精品一区二区亚洲| 国产精品成人观看视频国产奇米| 久久精品小视频| 欧洲日韩成人av| 97免费中文视频在线观看| 亚洲美女精品久久| 久久琪琪电影院| 久久久精品一区二区三区| 2018中文字幕一区二区三区| 日韩最新免费不卡| 在线视频国产日韩| 日本精品在线视频| 久久精品国产亚洲7777| 久久久精品国产| 亚洲国产精品一区二区久| 日韩视频免费中文字幕| 精品福利在线视频| 最近更新的2019中文字幕| 欧美精品激情在线| 色一区av在线| 日韩中文字在线| 欧美伊久线香蕉线新在线| 国产精品久久久久高潮| 午夜精品久久久久久久久久久久| 亚洲欧美国内爽妇网| 欧美在线一级va免费观看| 青青在线视频一区二区三区| 国产一区视频在线| 亚洲男人第一网站| 日韩av综合中文字幕| 91久久夜色精品国产网站| 亚洲欧美日韩综合| 国产精品久久久91| 亚洲人午夜色婷婷| 国产精品男人的天堂| 久久久国产一区| 欧美精品一本久久男人的天堂| 欧美激情女人20p| 97视频在线观看成人| 欧美日韩在线视频一区二区| 国自产精品手机在线观看视频| 国产98色在线| 久久这里只有精品视频首页| 欧美成人剧情片在线观看| 91免费在线视频| 日韩在线不卡视频| 日韩欧美在线中文字幕| 视频在线一区二区| 久久不射电影网| 亚洲网站在线观看| 日本精品视频在线| 91国自产精品中文字幕亚洲| 九九热精品在线| 久久久亚洲影院你懂的| 欧美激情亚洲另类| 国内精品模特av私拍在线观看| 2019中文字幕在线免费观看| 热久久这里只有| 精品国产欧美成人夜夜嗨| 欧美激情小视频| 国产亚洲成精品久久| 成人免费视频网址| 在线观看国产精品日韩av| 精品视频一区在线视频| 亚洲va国产va天堂va久久| 91在线观看免费网站| 97久久超碰福利国产精品…| 国语自产偷拍精品视频偷| 亚洲美女精品成人在线视频| 日韩av手机在线| 青青精品视频播放| 91久久精品国产| www.亚洲人.com| 91精品国产九九九久久久亚洲| 亚洲综合日韩中文字幕v在线| 亚洲石原莉奈一区二区在线观看| 自拍偷拍免费精品| 亚洲mm色国产网站| 国产精品亚洲精品| 国产精品九九久久久久久久| 久久久爽爽爽美女图片| 亚洲成色777777在线观看影院| 国模极品一区二区三区| 欧美日韩在线观看视频| 欧美香蕉大胸在线视频观看| 国产亚洲精品高潮| 欧美不卡视频一区发布| 日韩三级影视基地| 亚洲国产精品va在线| 亚洲第一区第二区| 日韩中文字幕在线播放| 亚洲精品大尺度| 日韩久久免费电影| 日韩极品精品视频免费观看| 欧美另类交人妖| 亚洲情综合五月天| 欧美巨乳美女视频| 丝袜一区二区三区| 亚洲天堂男人天堂女人天堂| 国产亚洲精品久久久优势| 欧美视频中文字幕在线| 亚洲最大福利视频| 欧美精品日韩三级| 亚洲影院高清在线| 国产精品精品视频一区二区三区| 另类图片亚洲另类| 国产999精品久久久影片官网| 日韩免费电影在线观看| 亚洲黄色免费三级| 久久综合九色九九| 亚洲国产日韩欧美在线图片| 欧美成人四级hd版| 日韩性xxxx爱| 亚洲v日韩v综合v精品v| 91在线观看免费高清| 亚洲电影在线看| 亚洲欧美日韩久久久久久| 欧美精品videosex性欧美| 欧美成人免费视频| 久久久久99精品久久久久| 国产精品高清免费在线观看| 丁香五六月婷婷久久激情| 日韩在线视频免费观看| 亚洲精品一区二区在线| 不卡伊人av在线播放| 欧美福利小视频| 欧美黄色成人网| 川上优av一区二区线观看| 精品国产一区二区三区久久狼黑人| 精品视频久久久| 国产精品青青在线观看爽香蕉| 亚洲精品午夜精品| 午夜精品福利电影| 一区二区三区黄色| 992tv在线成人免费观看| 日韩欧美在线观看| 日本韩国欧美精品大片卡二| 亚洲第一视频网站| 日韩精品免费观看| 日韩国产在线看| 国产精品一区专区欧美日韩| 欧美猛少妇色xxxxx| 色综合色综合网色综合| 亚洲精品少妇网址| 日韩高清中文字幕| 午夜精品美女自拍福到在线| 亚洲网站视频福利| 国产精品无av码在线观看| 91免费高清视频| 91亚洲精品久久久| 欧美怡春院一区二区三区| 45www国产精品网站| 国产一级揄自揄精品视频| 久久免费国产精品1| 亚洲一区二区三区成人在线视频精品| 法国裸体一区二区| 亚洲片在线观看| 一区二区亚洲欧洲国产日韩| 在线激情影院一区| 日本久久亚洲电影| 91免费在线视频| 亚洲va久久久噜噜噜久久天堂| 97在线免费视频|