<h2>開篇</h2>
很多的app都會使用wap頁面,一方面是app上線后臺可配置,一方面是Android和iOS可重用.這時JS和原生代碼之間數(shù)據(jù)的傳遞,就變得尤為重要.而JavaScriptCore.framework這個庫,就在iOS平臺中扮演著JS和native交互的橋梁的角色.
之前的項目代碼采用的方法是在webView的代理方法中攔截請求.
-(void)webViewDidFinishLoad:(UIWebView *)webView
通過URL的scheme判斷是否是用作交互的URL,通過query傳遞數(shù)據(jù).這種方式解決了JS和iOS交互的問題, 但是也有兩個缺點:
- 代碼繁瑣,不夠優(yōu)雅
- JS經(jīng)常會調(diào)不到native方法,和前端的同學溝通發(fā)現(xiàn),JS的onclick方法要setTimeOut 0.5毫秒,native方法才能夠被調(diào)用.
我們一直在尋求更好的方法,直到發(fā)現(xiàn)了JavaScriptCore.framework.
<h2>JavaScriptCore</h2>
javaScriptCore 是用來支持js和native交互的庫.通過JavaScriptCore Framework,可以用OC執(zhí)行JS,或者在JS中注入OC對象.
在JavaScriptCore頭文件中可以看到,JavaScriptCore主要由以下幾個類構成
- JSContext
JSContent 對象提供一個JS運行環(huán)境. - JSValue
JSValue對象是一個OC和JS數(shù)據(jù)類型相互轉(zhuǎn)換的橋梁.比如string->NSString,NSString->string.對應關系及轉(zhuǎn)化方法如下表:
- JSManagedValue
- JSVirtualMachine
- JSExport JSExport 實現(xiàn)了一個protocol.下面會主要用到這個協(xié)議.
<h4>JSExport</h4>
JSExport提供了一個把OC的對象的類方法實例方法\屬性注入到JS的方式.當一個實例遵循某個協(xié)議,而這個協(xié)議又繼承自JSExport的時候,就可以把協(xié)議中的方法注入到JS中,JSCore會自動的把OC的數(shù)據(jù)類型轉(zhuǎn)化為JS數(shù)據(jù)類型.這么說會有點繞,看下面的代碼:
#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h>
@protocol JsNativeBridgeDelegate <JSExport>
-(void)testLog:(NSString *)string;`
-(void)testTwo:(NSString *)str ArgLog:(NSInteger)count;
@end
@interface JsNativeBridge : NSObject<JsNativeBridgeDelegate>
+(instancetype)shareInstance;
@end
JsNativeBridgeDelegate繼承自協(xié)議JSExport,而JsNativeBridge有遵循了協(xié)議JsNativeBridgeDelegate.這時,把JsNativeBridge的對象注入JS后,就可以通過instnce.function的形式調(diào)用JsNativeBridgeDelegate協(xié)議里的方法.
在webView加載完成的代理中,取到wap的上下文,并向其中注入JsNativeBridge對象.
#pragma mark -- webView delegate
-(void)webViewDidFinishLoad:(UIWebView *)webView
{
JSContext *jscontext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
JSValue *jsObject = jscontext[@"iosJsBridge"];
if (![jsObject toBool]) {
jscontext[@"iosJsBridge"] = [JsNativeBridge shareInstance];
}
}
在html頁面,就能夠用iosJsBridge對象去調(diào)用JsNativeBridgeDelegate的方法了.
<button onclick="iosJsBridge.testLog('調(diào)用native方法')">jsToNative -testLog</button>
這樣就能夠調(diào)用到-(void)testLog:(NSString *)string;方法.參數(shù)為@"調(diào)用native方法".
當方法有多個參數(shù)時,JSCore會把OC的方法名中的":"(冒號)去掉,并且冒號后面第一個字母大寫,轉(zhuǎn)化為JS的方法.如果要調(diào)用-(void)testTwo:(NSString *)str ArgLog:(NSInteger)count;
,在JS中就要這么寫:iosJsBridge.testTwoArgLog('調(diào)用native多參數(shù)方法',100)
.
當方法中有多個參數(shù)的時候,OC的方法名就會變得很長,為了簡便,JSCore提供了一個宏**
JSExportAs(PropertyName, Selector) **,可以簡化方法名. JS通過iosJsBridge.PropertyName
調(diào)用方法Selector.
JSCore也可以把函數(shù)直接注入到JS中,或者很方便的執(zhí)行JS方法.有時間再寫吧....