日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

浅谈 JavaScriptCore

發布時間:2025/4/16 javascript 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 浅谈 JavaScriptCore 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

來源:XcodeMen(王瑞華) ??

鏈接:http://t.cn/RVqQI5p

?

本文由我們團隊的王瑞華童鞋撰寫。

?


?

OS X Mavericks 和 iOS 7 引入了 JavaScriptCore 庫,它把 WebKit 的 JavaScript 引擎用 Objective-C 封裝,提供了簡單,快速以及安全的方式接入世界上最流行的語言。在項目的實際開發中,由于需要與 H5 端有交互,所以采用了JavaScriptCore的交互方式,借此參與該項目的機會,對JavaScriptCore也有了一些簡單的了解。

?

JSContext/JSValue

?

JSContext 是 JavaScript 的執行環境。所有 JavaScript 執行發生的背景,以及所有 JavaScript 值被綁在這一個上下文中。JSContext 類似于 UIWindow 的概念,所有的執行都在改環境中發生:

?

JSContext *context = [[JSContext alloc] init];

[context evaluateScript:@"var num = 5 + 5"];

[context evaluateScript:@"var names = ['Grace', 'Ada', 'Margaret']"];

[context evaluateScript:@"var triple = function(value) { return value * 3 }"];

JSValue *tripleNum = [context evaluateScript:@"triple(num)"];

NSLog(@"Tripled: %d", [tripleNum toInt32]);

// Tripled: 30

?

代碼最后一行,每個 JSValue 起源于 JSContext 和 持有它的強引用。當一個 JSValue 實例方法創造一個新的 JSValue時,該新 JSValue 起源于同一個 JSContext。 JSValue 包裝了每一個可能的 JavaScript 值:字符串和數字;數組、對象和方法;甚至錯誤和特殊的 JavaScript 值諸如 null 和 undefined。

?

OBJECTIVE-C TYPEJAVASCRIPT TYPE
nilundefined
NSNullnull
NSStringstring
NSNumbernumber, boolean
NSDictionaryObject object
NSArrayArray object
NSDateDate object
NSBlock (1)Function object (1)
id (2)Wrapper object (2)
Class (3)Constructor object (3)

?

下標支持

?

作為下標傳遞的對象鍵將被轉換為一個 JavaScript 值, 然后值轉換為一個用作獲取屬性名稱的字符串。

?

JSValue *names = context[@"names"];

JSValue *initialName = names[0];

NSLog(@"The first name: %@", [initialName toString]);

// The first name: Grace

?

該簡易方法對應于以下兩個方法:

?

- (JSValue *)objectForKeyedSubscript:(id)key;

- (JSValue *)objectAtIndexedSubscript:(NSUInteger)index;

?

調用方法

?

JSValue 包裝了一個 JavaScript 函數,我們可以從 Objective-C 代碼中使用 Foundation 類型作為參數來直接調用該函數。

?

JSValue *tripleFunction = context[@"triple"];

JSValue *result = [tripleFunction callWithArguments:@[@5] ];

NSLog(@"Five tripled: %d", [result toInt32]);

?

JavaScript 調用

?

上面說明的 OC 調用 JavaScript 的方法。那么接下來,說明 JavaScript 訪問 OC 定義的對象和方法。我粗淺的認為就是在遵守該協議后,JavaScript 就可以調用 OC 實現的方法和屬性等。

?

讓 JSContext 訪問我們的本地客戶端代碼的方式主要有兩種:JSExport 協議和block。

?

JSExport 協議

?

JSExport 提供一個將 OC 中的類、實例方法和屬性等導出為 JavaScript 函數的方法。

?

該協議只包含了一個方法:

?

JSExportAs(PropertyName, Selector)

?

即當導出到 JavaScript 時,重命名一個 selector。

?

這就需要熟悉它的做法,當帶有一個或多個參數的 seletor 轉變為 JavaScript 的屬性名字時,在默認情況下一個屬性名字將采用以下方式生成:

?

  • 所有的冒號將從 Selector 當中移除掉

  • 任何一個后邊跟著冒號的小寫字母開頭的單詞將被改換為大寫。

?

在這種默認的轉換方式下,一個 selector 如 doFoo:withBar: 將被導為doFooWithBar 。這種默認的改變有可能被 JSExportAs 宏 所改寫,例如將 doFoo:withBar: 導出為 doFoo 。實際寫法如下:

?

@protocol MyClassJavaScriptMethods

????JSExportAs(doFoo,

????- (void)doFoo:(id)foo withBar:(id)bar

????);

@end

?

請注意 JSExport 宏只可能適用于帶有一個或更多的參數的selector。

?

Blocks

?

當一個 Objective-C block 被賦給 JSContext 里的一個標識符,JavaScriptCore 會自動的把 block 封裝在 JavaScript 函數里。如下:

?

JSContext *context = [[JSContext alloc] init];

????context[@"simplifyString"] = ^(NSString *input) {

????????NSMutableString *mutableString = [input mutableCopy];

????????CFStringTransform((__bridge CFMutableStringRef)mutableString, NULL, kCFStringTransformToLatin, NO);

????????return mutableString;

????};

NSLog(@"%@", [context evaluateScript:@"simplifyString('什么!')"]);

// shén me!

?

JSManagedValue 與內存管理

?

由于 block 可以保有變量引用,而且 JSContext 也強引用它所有的變量,為了避免強引用循環需要特別小心。OC 采用的是引用計數機制,而 JavaScript采用的垃圾回收機制。基于此項機制,便出現了 JSManagedValue ,它的主要用途是存儲一個 JSValue,這樣可以避免一個保留環的產生。

?

JavaScript 與 OC 交互的實際實例

?

在開發項目中,我們采用了 JavaScript 的方式完成了與 Native 的交互,使得比單純的運用 UIWebview 的 stringByEvaluatingJavaScriptFromString: 更加高效。

?

如上所述,讓 JSContext 訪問我們的本地客戶端代碼的方式主要有兩種:JSExport 協議和block。在我們項目中主要采用了 JSExport 的方式去實現。

?

1. JDRWebViewJSExportProtocol 和 JDRWebViewBaseHandler

?

我們的 JDRWebViewBaseHandler 類實現了 JDRWebViewJSExportProtocol 協議,該協議規定了那些方法或者屬性可在 JavaScript 中使用。

?

@protocol JDRWebViewJSExportProtocol

?

JSExportAs

(closeForJS /**H5調用的 Webview 關閉方法的別名**/,

@optional

- (void)close:(id)JSON callback:(JSValue*) callback

);

?

JSExportAs

(goBackForJS /**H5調用的 Webview 關閉方法的別名**/,

@optional

- (void)goBack:(id)JSON callback:(JSValue*) callback

);

@end

?

@interface JDRWebViewBaseHandler : NSObject

@property (nonatomic , weak) JDRWebViewController *webViewController;

?

-(instancetype)initWithWebViewController:(JDRWebViewController *) webViewController NS_DESIGNATED_INITIALIZER;

@end

?

@implementation JDRWebViewBaseHandler

-(instancetype)initWithWebViewController:(JDRWebViewController *) webViewController{

????if (self = [super init]) {

????????_webViewController = webViewController;

????}

????return self;

}

?

-(void)goBack:(id)JSON callback:(JSValue *)callback {

????WEAK_SELF(weakSelf);

????dispatch_async(dispatch_get_main_queue(), ^{

????????STRONG_SELF(strongSelf, weakSelf);

????????//判斷 backPressCallBack 是否已經設置 ,如果已經設置監聽方法 , 則執行 監聽回退的 JS 方法

????????if ([strongSelf.webViewController.webView canGoBack]) {

????????????[(UIWebView*)strongSelf.webViewController.webView stopLoading];

????????????[(UIWebView*)strongSelf.webViewController.webView goBack];

????????}else {

????????????[strongSelf close:nil callback:nil];

????????}

????});

}

-(void)close:(id)JSON callback:(JSValue *)callback {

????//目前關閉 WebView 方法不關注 callback 參數

????WEAK_SELF(weakSelf);

????dispatch_async(dispatch_get_main_queue(), ^{

????????STRONG_SELF(strongSelf, weakSelf);

????????if ([strongSelf.webViewController.navigationController???????????? popViewControllerAnimated:YES] == nil) {

????????????????[strongSelf.webViewController???????????????????????????? dismissViewControllerAnimated:YES completion:nil];

????????????}

????});

}

@end

?

2. JSContext 配置

?

然后,我們可以用我們已經創建的 JDRWebViewBaseHandler 類,我們需要將其導出到 JavaScript 環境中。

?

self.JSHandler = [[JDRWebViewBaseHandler alloc] initWithWebViewController:self];????

// 以 JSExport 協議關聯 native 的方法 *platform* 是暫時定義的關鍵字

self.context[@"platform"] = self.JSHandler;

?

3.在 H5 頁面中書寫 JavaScript 函數調用 OC

?

close: function() {

??platform.coselForJS();

}

?

結語

?

通常對于 JavaScript 與 OC 的交互,會采用 JavaScriptCore 包裝一層協議方法,原始一點的方法則是通過截取 UIWebView 的協議實現。隨著 iOS 8 之后 WKWebview的出現,又出現了一個新的方式,而對于 WKWebView 來說是不支持直接與 JavaScriptCore 交互的。通常采取 WKUserContentController 采用它的協議方法

?

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message

?

如果使用 WKWebview 的話,對于 H5 中的 JavaScript 寫法又需要改動為 window.webkit.messageHandlers..postMessage()。WKWebView 對于JavaScript 的調用只提供了一種方法:

?

- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler

?

目前項目中考慮到 應用 WKWebview 與 UIWebview + JavaScriptCore 調用方式的差異,暫時放棄了對于 WKWebview的支持。

?

參考

?

  • JavaScriptCore

    http://nshipster.cn/javascriptcore/

    ?

  • 轉載于:https://www.cnblogs.com/fengmin/p/5968435.html

    總結

    以上是生活随笔為你收集整理的浅谈 JavaScriptCore的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。