OC 與 JS 交互之 JavaScriptCore

JavaScriptCore 是 JavaScript 的虛擬機(jī),是一個(gè)WebKit的運(yùn)行環(huán)境,為 JavaScript 的執(zhí)行提供底層資源。我們可以利用 JavaScriptCore 中的類(lèi)及協(xié)議,進(jìn)行 OC 與 JS 的交互。

JavaScriptCore中類(lèi)及協(xié)議:
JSContext

給JavaScript提供運(yùn)行的上下文環(huán)境,像是前端開(kāi)發(fā)中的面對(duì)瀏覽器的 window 對(duì)象,代表運(yùn)行時(shí)的一個(gè)全局變量;
通過(guò) -evaluateScript: 方法就可以執(zhí)行一JS代碼,其返回值是JavaScript代碼中最后一個(gè)生成的值;
JSContext的exceptionHandler屬性可用來(lái)接收J(rèn)avaScript中拋出的異常

JSValue

封裝了JS與OC中的對(duì)應(yīng)的類(lèi)型,一個(gè)用來(lái)處理iOS中所有可能存在的JavaScript執(zhí)行后產(chǎn)生Value的類(lèi),可以用來(lái)轉(zhuǎn)換基本數(shù)據(jù)類(lèi)型

JSManagedValue

管理數(shù)據(jù)和方法的類(lèi),包含一個(gè)JSValue對(duì)象,有條件地持有對(duì)象

JSVirtualMachine

完整獨(dú)立的JavaScript執(zhí)行環(huán)境,為JavaScript的執(zhí)行提供底層資源,實(shí)現(xiàn)并發(fā)的JavaScript執(zhí)行,JavaScript和OC橋接對(duì)象的內(nèi)存管理

JSExport

這是一個(gè)協(xié)議,如果采用協(xié)議的方法交互,自己定義的協(xié)議必須遵守此協(xié)議,在協(xié)議中聲明的API都會(huì)在JS中暴露出來(lái),才能調(diào)用

OC調(diào)用JS
JSContext *context = [[JSContext alloc] init];
[context evaluateScript:@"function add(a,b) {return a + b;}"];
    
//1.取出方法名,調(diào)用
JSValue *add = context[@"add"];
JSValue *sum = [add callWithArguments:@[@7,@8]];
NSLog(@"Sum1: %d", [sum toInt32]);
    
//2.將調(diào)用過(guò)程繼續(xù)寫(xiě)進(jìn)JSContext里,調(diào)用
JSValue *addValue = [context evaluateScript:@"add(7, 8)"];
NSLog(@"Sum2: %@", addValue.toNumber);
JS調(diào)用OC

1.block方式

JSContext *context = [[JSContext alloc] init];
context[@"log"] = ^(){
    NSLog(@"----------Begin log----------");
    NSArray *args = [JSContext currentArguments];
    for (JSValue *jsVal in args) {
        NSLog(@"%@", jsVal);
    }
        
    JSValue *this = [JSContext currentThis];
    NSLog(@"This: %@", this);
    NSLog(@"-----------End log-----------");
};

//web 頁(yè)面可調(diào)用 log 方法,傳入相關(guān)參數(shù),調(diào)用OC端的block,這里直接用 JSContext 執(zhí)行 JS 代碼
[context evaluateScript:@"log('apple',['array1', 'array2'],{key1:'value1',key2:'value2',key3:'value3'});"];
用 block 方式使 JS 調(diào)用 OC 代碼

從圖中可以看出,JSValue 對(duì)于 JS 類(lèi)型到 OC 類(lèi)型的處理并不一致,具體如下:

JSValue 作為 OC 類(lèi)型與 JS 類(lèi)型的橋梁

2.使用 webview
首先,在工程中新建一個(gè) Empty 文件,命名為 test.html ,代碼如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
            <title>test javascript</title>
    </head>
    <body>
        <div>
            <button onclick="zn.a('JS與OC交互');">請(qǐng)看xcode的log</button>
        </div>
    </body>
</html>

然后,新建一個(gè) model 類(lèi),此類(lèi)必須遵守一個(gè)‘遵守 JSExport 協(xié)議’的協(xié)議,如果想要將一個(gè)自定義類(lèi)的方法暴露給外部的JavaScript使用,那么這個(gè)類(lèi)必須遵守JSExport協(xié)議,JSExport協(xié)議提供了一種聲明式的方法去向JavaScript代碼導(dǎo)出Objective-C的實(shí)例類(lèi)及其實(shí)例方法,類(lèi)方法和屬性:

@protocol PersonJSExport <JSExport>
//將 JS 中的調(diào)用方法名與model類(lèi)中的相對(duì)應(yīng)
JSExportAs(a, - (void)nslog:(NSString *)string);
@end

在model類(lèi)中實(shí)現(xiàn)協(xié)議:

- (void)nslog:(NSString *)string
{
    NSLog(@"%@", string);
}

最后,在 controller 中新添一個(gè) webview ,這個(gè) webview 加載剛剛新建的 test.html 中的內(nèi)容:

- (UIWebView *)webView
{
    if (_webView == nil) {
        _webView = [[UIWebView alloc] initWithFrame:self.view.frame];
        
        NSURL *baseURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
        NSString *htmlContent = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"test" ofType:@"html"] encoding:NSUTF8StringEncoding error:nil];
        
        [_webView loadHTMLString:htmlContent baseURL:baseURL];
       
        JSContext *context = [_webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
        JsObjCModel *jsOCModel = [JsObjCModel new];
        //給js中的對(duì)象賦值
        context[@"zn"] = jsOCModel;
    }
    return _webView;
}

JSContext 是通過(guò) webView 的 valueForKeyPath 獲取的,其路徑為documentView.webView.mainFrame.javaScriptContext;
將一個(gè)初始化好的、可以執(zhí)行協(xié)議中方法的model類(lèi)賦值給 JS 中定義的一個(gè)對(duì)象,在點(diǎn)擊 html 頁(yè)面上的 button 后,JS 執(zhí)行 OC 方法。

屏幕快照 2017-08-17 下午9.17.31.png

參考博客:
JavaScriptCore全面解析
JavaScriptCore
WebView 與 JS 的幾種交互

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容