小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

利用 JavaScriptCore 讓 Web 與 Native 交互更便捷

 jerry_tom123 2016-01-15

還記得以前在網(wǎng)頁上用 iframe 指定一個 URL 并通過 native 的 - webView:shouldStartLoadWithRequest:navigationType: 回調(diào)方法攔截請求,再蛋疼的各種截取和判斷字符串,結(jié)合 json 結(jié)構(gòu)的字符串來獲取 web 端發(fā)來的數(shù)據(jù)。
通過 - stringByEvaluatingJavaScriptFromString: 來拼接老長的字符串來傳遞數(shù)據(jù)給 web 端嗎。。。

現(xiàn)在我們可以對這種方式說 「愛過~」 了。

先看一下 Objective-C 與 JavaScript 之間類型的對應(yīng)關(guān)系

Objective-C type JavaScript type
nil undefined
NSNull null
NSString string
NSNumber number, boolean
NSDictionary Object object
NSArray Array object
NSDate Date object
NSBlock Function object
id Wrapper object
Class Constructor object

返回的 JSValue 轉(zhuǎn)換為 Objective-C 類型的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- (BOOL)toBool;

- (double)toDouble;

- (int32_t)toInt32;

- (uint32_t)toUInt32;

- (NSNumber *)toNumber;

- (NSString *)toString;

- (NSDate *)toDate;

- (NSArray *)toArray;

- (NSDictionary *)toDictionary;

- (id)toObject;

- (id)toObjectOfClass:(Class)expectedClass;

我們主要使用的是 JSContext 這個類,下面通過幾個簡單的例子來演示。

首先需要加入 JavaScriptCore.framework 并引入。

1
#import <JavaScriptCore/JavaScriptCore.h>

Objective-C 調(diào)用純 JavaScript

例如有一段計算階乘的腳本

test.js
1
2
3
4
5
6
7
8
9
function factorial(n) {
  if (n < 0){
      return;
  }
  if (n === 0){
      return 1;
  }
  return n * factorial(n - 1)
};

將腳本文件拖入項目。

注意在項目的 TARGETS > Build Phases 中,把 *.js 文件從 Compile Sources 都拖到 Copy Bundle Resources,否則會有編譯警告。

通過 - evaluateScript: 方法把腳本引入 JSContext 對象

1
2
3
4
5
6
NSString *path = [[[NSBundle mainBundle] bundlePath]  stringByAppendingPathComponent:@"test.js"];

NSString *testScript = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];

self.context = [[JSContext alloc] init];
[self.context evaluateScript:testScript];

通過 - objectForKeyedSubscript: 傳入 function 的名稱以取到該方法, 再通過 - callWithArguments: 傳入?yún)?shù)并得到返回值(如果有)。

1
2
3
4
5
6
NSNumber *inputNumber = [NSNumber numberWithInteger:[self.inputNumberTextField.text integerValue]];

JSValue *function = [self.context objectForKeyedSubscript:@"factorial"];
JSValue *result = [function callWithArguments:@[inputNumber]];

NSNumber *number = [result toNumber];

JavaScript 調(diào)用 native 代碼

  • JSExport

首先通過一個協(xié)議來關(guān)聯(lián) JavaScript 的 function 和 native 方法,

還可通過 JSExportAs(functionName, Selector); 來指定 function 的別名。

1
2
3
4
5
6
7
8
9
10
11
12
@protocol TestJSExport <JSExport>

JSExportAs
(functionNameForJS /** JavaScript function 的別名 */,

- (void)handleFactorialCalculateWithNumber:(NSNumber *)number

);

- (void)pushToNextViewControllerWithTitle:(NSString *)title;

@end

然后在 UIWebView 回調(diào)方法 - webViewDidFinishLoad: 中把 web 的 javaScriptContext 與我們用來操作的 JSContext 對象關(guān)聯(lián),并把 self 設(shè)為 JavaScript 調(diào)用 function 的對象。

1
2
3
4
5
self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

// 以 JSExport 協(xié)議關(guān)聯(lián) native 的方法
self.context[@"native"] = self;
//此處有誤,關(guān)聯(lián)到 self 會造成 self 這個對象無法釋放的問題,建議使用后面的 block 形式,或者關(guān)聯(lián)到非 self 本身的對象。(weakSelf 也不行)

這樣在 web 中我們就可以通過所注冊的 native 對象來調(diào)用到 native 方法。

1
2
3
4
5
6
7
<textarea  id="input" style="font-size:10pt;color:black;"></textarea>

<input type="button" value="計算階乘" onclick="native.functionNameForJS(input.value);" />

<a id="push" href="#" onclick="native.pushToNextViewControllerWithTitle('Next VC');">
    push to next ViewController
</a>

建議使用后面的 block 形式,或者關(guān)聯(lián)到非 self 本身的對象。(weakSelf 也不行)

  • Block

同樣的,先關(guān)聯(lián) javaScriptContext ,然后直接給 JSContext 對象 - setObject:forKeyedSubscript: 來設(shè)定相應(yīng) block。

1
2
3
4
5
self.context[@"log"] =
^(NSString *str)
{
    NSLog(@"%@", str);
};

這樣在 web 中我們就可以直接調(diào)用上面注冊的 function

1
<input type="button" value="測試log" onclick="log('測試');" />

使用 Block 要注意避免循環(huán)引用

  • 捕獲異常

JSContextexceptionHandler 屬性賦予相應(yīng) Block

1
2
3
4
5
6
self.context.exceptionHandler =
^(JSContext *context, JSValue *exceptionValue)
{
    context.exception = exceptionValue;
    NSLog(@"%@", exceptionValue);
};

我們可以來利用一些開源的 JavaScript 庫來做一些比 native 代碼更方便和易于實現(xiàn)的東西

隨便找了一個 Highcharts 圖表庫來做例子。

注意:Highcharts 開源但不完全免費。個人用戶及非商業(yè)用途免費,商業(yè)用途需要購買許可。

大致的調(diào)用代碼如下

1
2
3
4
5
6
7
8
9
NSArray *the1024Data = @[@33, @41, @32, @51, @42, @103, @136];
NSDictionary *the1024Dict = @{@"name": @"1024", @"data": the1024Data};

NSArray *theCCAVData = @[@8, @11, @21, @13, @20, @52, @43];
NSDictionary *theCCAVDict = @{@"name": @"CCAV", @"data": theCCAVData};

NSArray *seriesArray = @[the1024Dict, theCCAVDict];

[self.context[@"drawChart"] callWithArguments:@[seriesArray]];
1
2
3
4
function drawChart (seriesArray)
{
  ...
}

詳細的代碼就不貼了,見項目 JavaScriptCoreSample 。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多