前言
ObjectiveC與Js交互是常見的需求功氨,可對于新手或者所謂的高手而言镜会,其實并不是那么簡單明了炫刷。這里只介紹iOS7.0后出來的JavaScriptCore framework毕荐。
關于JavaScriptCore
本教程中所涉及到的幾種類型:
JSContext, JSContext是代表JS的執(zhí)行環(huán)境翘地,通過-evaluateScript:方法就可以執(zhí)行一JS代碼
JSValue, JSValue封裝了JS與ObjC中的對應的類型,以及調用JS的API等
JSExport, JSExport是一個協(xié)議滚粟,遵守此協(xié)議寻仗,就可以定義我們自己的協(xié)議,在協(xié)議中聲明的API都會在JS中暴露出來坦刀,才能調用
ObjC與JS交互方式
通過JSContext愧沟,我們有兩種調用JS代碼的方法:
1、直接調用JS代碼
2鲤遥、在ObjC中通過JSContext注入模型沐寺,然后調用模型的方法
直接調用JS代碼
// 一個JSContext對象,就類似于Js中的window盖奈,// 只需要創(chuàng)建一次即可混坞。self.jsContext= [[JSContext alloc] init];//? jscontext可以直接執(zhí)行JS代碼。[self.jsContextevaluateScript:@"var num = 10"]; [self.jsContextevaluateScript:@"var squareFunc = function(value) { return value * 2 }"];// 計算正方形的面積JSValue *square = [self.jsContextevaluateScript:@"squareFunc(num)"];// 也可以通過下標的方式獲取到方法JSValue *squareFunc =self.jsContext[@"squareFunc"]; JSValue *value = [squareFunc callWithArguments:@[@"20"]];NSLog(@"%@", square.toNumber);NSLog(@"%@", value.toNumber);
這種方式是沒有注入模型到JS中的钢坦。這種方式使用起來不太合適究孕,通常在JS中有很多全局的函數(shù),為了防止名字重名爹凹,使用模型的方式是最好不過了厨诸。通過我們協(xié)商好的模型名稱,在JS中直接通過模型來調用我們在ObjC中所定義的模型所公開的API禾酱。
通過注入模型的方式交互
首先微酬,我們需要先定義一個協(xié)議绘趋,而且這個協(xié)議必須要遵守JSExport協(xié)議。
@protocolJavaScriptObjectiveCDelegate// JS調用此方法來調用OC的系統(tǒng)相冊方法- (void)callSystemCamera;// 在JS中調用時颗管,函數(shù)名應該為showAlertMsg(arg1, arg2)// 這里是只兩個參數(shù)的陷遮。- (void)showAlert:(NSString*)title msg:(NSString*)msg;// 通過JSON傳過來- (void)callWithDict:(NSDictionary*)params;// JS調用Oc,然后在OC中通過調用JS方法來傳值給JS垦江。- (void)jsCallObjcAndObjcCallJsWithDict:(NSDictionary*)params;@end
接下來帽馋,我們還需要定義一個模型:
// 此模型用于注入JS的模型,這樣就可以通過模型來調用方法比吭。@interfaceHYBJsObjCModel:NSObject@property(nonatomic,weak) JSContext *jsContext;@property(nonatomic,weak)UIWebView*webView;@end
實現(xiàn)這個模型:
@implementationHYBJsObjCModel- (void)callWithDict:(NSDictionary*)params {NSLog(@"Js調用了OC的方法绽族,參數(shù)為:%@", params);}// Js調用了callSystemCamera- (void)callSystemCamera {NSLog(@"JS調用了OC的方法,調起系統(tǒng)相冊");// JS調用后OC后梗逮,又通過OC調用JS项秉,但是這個是沒有傳參數(shù)的JSValue *jsFunc =self.jsContext[@"jsFunc"]; [jsFunc callWithArguments:nil];}- (void)jsCallObjcAndObjcCallJsWithDict:(NSDictionary*)params {NSLog(@"jsCallObjcAndObjcCallJsWithDict was called, params is %@", params);// 調用JS的方法JSValue *jsParamFunc =self.jsContext[@"jsParamFunc"]; [jsParamFunc callWithArguments:@[@{@"age": @10, @"name": @"lili", @"height": @158}]];}- (void)showAlert:(NSString*)title msg:(NSString*)msg {dispatch_async(dispatch_get_main_queue(), ^{? UIAlertView *a = [[UIAlertView alloc] initWithTitle:title message:msg delegate:nilcancelButtonTitle:@"Ok"otherButtonTitles:nil,nil];? [a show]; });}@end
接下來绣溜,我們在controller中在webview加載完成的代理中慷彤,給JS注入模型。
#pragma mark - UIWebViewDelegate- (void)webViewDidFinishLoad:(UIWebView*)webView {self.jsContext= [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];// 通過模型調用方法怖喻,這種方式更好些底哗。HYBJsObjCModel *model? = [[HYBJsObjCModel alloc] init];self.jsContext[@"OCModel"] = model; model.jsContext=self.jsContext; model.webView=self.webView;self.jsContext.exceptionHandler= ^(JSContext *context, JSValue *exceptionValue) {? context.exception= exceptionValue;NSLog(@"異常信息:%@", exceptionValue); };}
我們是通過webView的valueForKeyPath獲取的,其路徑為documentView.webView.mainFrame.javaScriptContext锚沸。
這樣就可以獲取到JS的context跋选,然后為這個context注入我們的模型對象。
我們先寫兩個JS方法:
varjsFunc =function(){alert('Objective-C call js to show alert'); }varjsParamFunc =function(argument){document.getElementById('jsParamFuncSpan').innerHTML? = argument['name']; }
這里我們定義了兩個JS方法哗蜈,一個是jsFunc前标,不帶參數(shù)。
另一個是jsParamFunc距潘,帶一個參數(shù)炼列。
接下來,我們在html中的body中添加以下代碼:
Test how to use objective-c call js
現(xiàn)在就可以測試代碼了音比。
當我們點擊第一個按鈕:Call ObjC system camera時俭尖,
通過OCModel.callSystemCamera(),就可以在HTML中通過JS調用OC的方法洞翩。
在OC代碼中稽犁,我們的callSystemCamera方法體中,添加了以下兩行代碼骚亿,就是獲取HTML中所定義的JS就去jsFunc已亥,然后調用它。
JSValue*jsFunc =self.jsContext[@"jsFunc"]; [jsFunccallWithArguments:nil];
這樣就可以在JS調用OC方法時来屠,也讓OC反饋給JS虑椎。
看看下面?zhèn)髯值鋮?shù):
- (void)jsCallObjcAndObjcCallJsWithDict:(NSDictionary*)params {NSLog(@"jsCallObjcAndObjcCallJsWithDict was called, params is %@", params);// 調用JS的方法JSValue *jsParamFunc =self.jsContext[@"jsParamFunc"]; [jsParamFunc callWithArguments:@[@{@"age": @10, @"name": @"lili", @"height": @158}]];}
獲取我們在HTML中定義的jsParamFunc方法秫舌,然后調用它并傳了一個字典作為參數(shù)。
好了绣檬,就講這么多吧足陨,如果想要Demo源代碼,請到
github:https://github.com/CoderJackyHuang/IOSCallJsOrJsCallIOS