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相互調用總結
注:本文著作權歸作者,由demo大師代發,拒絕轉載,轉載需要作者授權