本教程中所涉及到的幾種類型:
JSContext, JSContext是代表JS的執(zhí)行環(huán)境,通過-evaluateScript:方法就可以執(zhí)行一JS代碼
JSValue, JSValue封裝了JS與ObjC中的對應的類型该园,以及調(diào)用JS的API等
JSExport, JSExport是一個協(xié)議,遵守此協(xié)議洋腮,就可以定義我們自己的協(xié)議塔拳,在協(xié)議中聲明的API都會在JS中暴露出來,才能調(diào)用
ObjC與JS交互方式
通過JSContext,我們有兩種調(diào)用JS代碼的方法:
1陌兑、直接調(diào)用JS代碼
2、在ObjC中通過JSContext注入模型由捎,然后調(diào)用模型的方法
直接調(diào)用JS代碼
// 一個JSContext對象兔综,就類似于Js中的window,
// 只需要創(chuàng)建一次即可。
self.jsContext = [[JSContext alloc] init];
//? jscontext可以直接執(zhí)行JS代碼软驰。
[self.jsContext evaluateScript:@"var num = 10"];
[self.jsContext evaluateScript:@"var squareFunc = function(value) { return value * 2 }"];
// 計算正方形的面積
JSValue *square = [self.jsContext evaluateScript:@"squareFunc(num)"];
// 也可以通過下標的方式獲取到方法
JSValue *squareFunc = self.jsContext[@"squareFunc"];
JSValue *value = [squareFunc callWithArguments:@[@"20"]];
NSLog(@"%@", square.toNumber);
NSLog(@"%@", value.toNumber);
這種方式是沒有注入模型到JS中的涧窒。這種方式使用起來不太合適,通常在JS中有很多全局的函數(shù)碌宴,為了防止名字重名杀狡,使用模型的方式是最好不過了。通過我們協(xié)商好的模型名稱贰镣,在JS中直接通過模型來調(diào)用我們在ObjC中所定義的模型所公開的API呜象。
通過注入模型的方式交互
首先,我們需要先定義一個協(xié)議碑隆,而且這個協(xié)議必須要遵守JSExport協(xié)議恭陡。
@protocol JavaScriptObjectiveCDelegate// JS調(diào)用此方法來調(diào)用OC的系統(tǒng)相冊方法
- (void)callSystemCamera;
// 在JS中調(diào)用時,函數(shù)名應該為showAlertMsg(arg1, arg2)
// 這里是只兩個參數(shù)的上煤。
- (void)showAlert:(NSString *)title msg:(NSString *)msg;
// 通過JSON傳過來
- (void)callWithDict:(NSDictionary *)params;
// JS調(diào)用Oc休玩,然后在OC中通過調(diào)用JS方法來傳值給JS。
- (void)jsCallObjcAndObjcCallJsWithDict:(NSDictionary *)params;
@end
接下來劫狠,我們還需要定義一個模型:// 此模型用于注入JS的模型拴疤,這樣就可以通過模型來調(diào)用方法。@interface HYBJsObjCModel : NSObject@property (nonatomic, weak) JSContext *jsContext;
@property (nonatomic, weak) UIWebView *webView;
@end
實現(xiàn)這個模型:
@implementation HYBJsObjCModel
- (void)callWithDict:(NSDictionary *)params {
NSLog(@"Js調(diào)用了OC的方法独泞,參數(shù)為:%@", params);
}
// Js調(diào)用了callSystemCamera
- (void)callSystemCamera {
NSLog(@"JS調(diào)用了OC的方法呐矾,調(diào)起系統(tǒng)相冊");
// JS調(diào)用后OC后,又通過OC調(diào)用JS懦砂,但是這個是沒有傳參數(shù)的
JSValue *jsFunc = self.jsContext[@"jsFunc"];
[jsFunc callWithArguments:nil];
}
- (void)jsCallObjcAndObjcCallJsWithDict:(NSDictionary *)params {
NSLog(@"jsCallObjcAndObjcCallJsWithDict was called, params is %@", params);
// 調(diào)用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:nil cancelButtonTitle:@"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"];
// 通過模型調(diào)用方法罚随,這種方式更好些。
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方法:
var jsFunc = function() {
alert('Objective-C call js to show alert');
}
var jsParamFunc = 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調(diào)用OC的方法糙麦。在OC代碼中辛孵,我們的callSystemCamera方法體中,添加了以下兩行代碼赡磅,就是獲取HTML中所定義的JS就去jsFunc魄缚,然后調(diào)用它。 JSValue *jsFunc = self.jsContext[@"jsFunc"]; [jsFunc callWithArguments:nil];這樣就可以在JS調(diào)用OC方法時焚廊,也讓OC反饋給JS冶匹。看看下面?zhèn)髯值鋮?shù):
- (void)jsCallObjcAndObjcCallJsWithDict:(NSDictionary *)params { NSLog(@"jsCallObjcAndObjcCallJsWithDict was called, params is %@", params); // 調(diào)用JS的方法 JSValue *jsParamFunc = self.jsContext[@"jsParamFunc"]; [jsParamFunc callWithArguments:@[@{@"age": @10, @"name": @"lili", @"height": @158}]];}獲取我們在HTML中定義的jsParamFunc方法咆瘟,然后調(diào)用它并傳了一個字典作為參數(shù)嚼隘。