JS與原生OC/Swift相互調用總結


代碼地址如下:
http://www.demodashi.com/demo/12754.html

JS-OC-Swift

JS和OC/Swift相互調用,主要總結了JS和OC交互的三種方式

1.使用UIWebView,利用JavaScriptCore實現

2.使用WKWebView,利用WKScriptMessageHandler實現

3.使用第三方框架WebViewJavascriptBridge實現

部分效果圖

JavaScriptCore

JavaScriptCore介紹

JavaScriptCore框架是基於webkit中以C/C++實現的JavaScriptCore的一個包裝,該框架讓Objective-C和JavaScript代碼直接的交互變得更加的簡單方便,主要由下面幾個類組成。

**1.JSContext **
JS執行的環境,同時也通過JSVirtualMachine管理着所有對象的生命周期,每個JSValue都和JSContext相關聯並且強引用context。可以通過[webView valueForKeyPath:@”documentView.webView.mainFrame.javaScriptContext”]來從webview上獲取相應的JSContext。

**2.JSValue **
JS對象在JSVirtualMachine中的一個強引用,其實就是Hybird對象。我們對JS的操作都是通過它。並且每個JSValue都是強引用一個context。同時,OC和JS對象之間的轉換也是通過它。

**3.JSManagedValue **
JS和OC對象的內存管理輔助對象。由於JS內存管理是垃圾回收,並且JS中的對象都是強引用,而OC是引用計數。如果雙方相互引用,勢必會造成循環引用,而導致內存泄露。我們可以用JSManagedValue保存JSValue來避免。

**4.JSVirtualMachine **
JS運行的虛擬機,有獨立的堆空間和垃圾回收機制。

**5.JSExport **
一個協議,如果JS對象想直接調用OC對象里面的方法和屬性,那么這個OC對象只要實現這個JSExport協議就可以了。

在Swift中獲取JS的context

context = webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as? JSContext

注入JS需要的對象,對象命名與html中使用的保持一致.self是遵守了JSExport協議,也可是其他遵守協議的對象。

context?.setObject(self, forKeyedSubscript:  "OC" as NSCopying & NSObjectProtocol)

JS調用Swift的方法,在Swift中實現協議

@objc protocol JSDelegate :JSExport {
    //包含參數的func,需要注意參數名對函數名稱的影響
    func showMessageToYou(_ message:String)
    
    /*
     對應html中“showAAndB”,此方法包含兩個參數,需要在參數前加“_”
     func showA(_ aString: String, andB: String)
     func showAAndB(_ aString:String,_ bStr:String)
     以上兩個方法等同
     */
    func showAAndB(_ aString:String,_ bStr:String)
    
    func doActionCallBack()
}

Swift調用JS的方法

let jsStr = String(format:"callback('%@')",(textField?.text)!)
self.context?.evaluateScript(jsStr)

OC中可使用block和實現JSExport協議兩種方式實現,代碼實現:

JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
self.context = context;
//注入JS需要的“OC”對象,該對象與html中的保持一致即可
self.context[@"OC"] = self;

WKScriptMessageHandler

初始化WKWebView后,添加供js調用oc/Swift的橋梁,這里的name對應WKScriptMessage中的name

webView.configuration.userContentController.add(_ scriptMessageHandler: WKScriptMessageHandler, name: String)

遵守協議WKScriptMessageHandler,實現以下方法,可實現JS把消息發送給OC/Swift。

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)

OC/Swift調用JS

let jsStr = String(format:"callback('%@')",(textField?.text)!)
self.webView.evaluateJavaScript(jsStr as String, completionHandler: { (result:Any?, error:Error?) in
       print("error:",error as Any)
 })

WebViewJavascriptBridge

WebViewJavascriptBridge是一個Objective-C與JavaScript進行消息互通的第三方庫,可以很方便的實現OC和Javascript互調的功能。WebViewJavascriptBridge實現互調的過程也容易理解,就是在OC環境和Javascript環境各自保存一個相互調用的bridge對象,每一個調用之間都有id和callbackid來找到兩個環境對應的處理。從Github上下載源碼之后,可以看到核心類主要包含如下幾個:

WebViewJavascriptBridge_JS:Javascript環境的Bridge初始化和處理。負責接收OC發給Javascript的消息,並且把Javascript環境的消息發送給OC。

WKWebViewJavascriptBridge/WebViewJavascriptBridge:主要負責OC環境的消息處理,並且把OC環境的消息發送給Javascript環境。

WebViewJavascriptBridgeBase:主要實現了OC環境的Bridge初始化和處理。

初始化WKWebViewJavascriptBridge

self.webViewBridge = [WKWebViewJavascriptBridge bridgeForWebView:self.webView];
[self.webViewBridge setWebViewDelegate:self];

JS調用OC需要注冊事件

[self.webViewBridge registerHandler:@"handlerName" handler:^(id data, WVJBResponseCallback responseCallback) {
   //code
}];

OC調用JS

[self.webViewBridge callHandler:@"handlerName" data:@[textField.text] responseCallback:^(id responseData) {
        NSLog(@"%@",responseData);
 }];

html中需要放置以下代碼

/*這段代碼是固定的,必須要放到js中*/
function setupWebViewJavascriptBridge(callback) {
    if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
    if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
    window.WVJBCallbacks = [callback];
    var WVJBIframe = document.createElement('iframe');
    WVJBIframe.style.display = 'none';
    WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
    document.documentElement.appendChild(WVJBIframe);
    setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
}
/*與OC交互的所有JS方法都要放在此處注冊,才能調用通過JS調用OC或者讓OC調用這里的JS*/
setupWebViewJavascriptBridge(function(bridge) {
     bridge.registerHandler('callback', function(data, responseCallback) {
        callback(data);
        responseCallback('js執行過了'+data);
    })
})

項目結構

JS與原生OC/Swift相互調用總結

代碼地址如下:
http://www.demodashi.com/demo/12754.html

注:本文著作權歸作者,由demo大師代發,拒絕轉載,轉載需要作者授權


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM