本人有若干成套学习视频, 可试看! 可试看! 可试看, 重要的事情说三遍 包含Java, 数据结构与算法, iOS, 安卓, python, flutter等等, 如有需要, 联系微信tsaievan.
<一>WebViewJavascriptBridge
WebViewJavascriptBridge是一套在UIWebView和WKWebView上都可以兼容的与JS交互的框架
OC与JS交互无非就是两种情况:
-
OC调用JS方法 -
JS调用OC方法
在这套框架中, 作者巧妙地设计了bridge这个对象, 相当于将OC和JS两端用桥连接了起来, bridge这个对象是两端共有的, 不管是在OC的代码中, 还是JS代码中, bridge指针都指向同一个对象
如下图所示:

那么当我OC端去调JS端方法时, 这个方法首先要在JS端注册.
如下图所示: Call handler是一个原生按钮, 再点击这个按钮的时候, 我需要调用JS的方法, 并上传参数. 那么这个JS方法首先就应该在JS端注册

JS端代码:
bridge.registerHandler('testJavascriptHandler', function(data, responseCallback) {
log('ObjC called testJavascriptHandler with', data)
var responseData = { 'res':'Right back atcha!' }
log('JS responding with', responseData)
responseCallback(responseData)
})
JS端注册了方法之后, 就相当于(请注意, 是相当于 !!!)给bridge添加了一个block, bridge现在持有这个block. 但并没有调用, 那什么时候调用呢. 就是OC端去调用的时候:
OC端代码:
- (void)callHandler:(id)sender {
id data = @{ @"greetingFromObjC": @"Hi there, JS!" };
[_bridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) {
NSLog(@"testJavascriptHandler responded: %@", response);
}];
}
这个方法就相当于调用了JS端的testJavascriptHandler方法, 并上传了@{ @"greetingFromObjC": @"Hi there, JS!" }这样一个字典参数.
如果是JS端去调用OC的方法呢?

同理, OC端就要去先注册这个方法:
[_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"testObjcCallback called: %@", data);
responseCallback(@"Response from testObjcCallback");
}];
这个注册方法和之前JS端的那个注册是一模一样的
然后JS端在适当的时候调用方法
callbackButton.onclick = function(e) {
e.preventDefault()
log('JS calling handler "testObjcCallback"')
bridge.callHandler('testObjcCallback', {'foo': 'bar'}, function(response){})
}
就是这么简单, 轻松, 还有easy
<二>WebKit原生框架
WebKit新增了一个WKUserContentController这个类, 这个类其实就类似于WebViewJavascriptBridge中的bridge, 只不过, 它实用的是代理的方式:
JS端调用OC方法:
WKUserContentController *ucc = self.webView.configuration.userContentController;
[ucc addScriptMessageHandler:self name:kShare];
[ucc addScriptMessageHandler:self name:kClose];
[ucc addScriptMessageHandler:self name:kGoMarket];
[ucc addScriptMessageHandler:self name:kNeedLogin];
[ucc addScriptMessageHandler:self name:kShareImage];
[ucc addScriptMessageHandler:self name:kTryOutVIP];
[ucc addScriptMessageHandler:self name:kShareWebView];
以上是我们公司的部分代码, addScriptMessageHandler :方法是注册代理, 监听JS那边的事件处理, 当JS需要调用OC代码时, 就会走回调方法:
- (void)userContentController:(WKUserContentController *)userContentController
didReceiveScriptMessage:(WKScriptMessage *)message
{
if ([message.name isEqualToString:kShare]) {
//
}
else if ([message.name isEqualToString:kShareImage]) {
//
}
else if ([message.name isEqualToString:kGoMarket]) {
//
}
else if ([message.name isEqualToString:kNeedLogin]) {
//
}
else if ([message.name isEqualToString:kShareWebView]) {
//
}
回调方法中message.name就是JS端需要调用的OC方法, message.body就是JS端回传给OC端的json参数.
OC端调用JS端代码:
NSString *scriptStr = [NSString stringWithFormat:@"DoAppAction('%@',{'status':false});", @"shared"];
[self.webView evaluateJavaScript:scriptStr completionHandler:nil];
以上代码是分享成功后需要调用的JS方法, 主要还是使用evaluateJavaScript: completionHandler:方法来完成OC端对JS端的交互
<三>JavaScriptCore
JavaScriptCore这个框架是用在UIWebView上的, 在WKWebView上却不适用.
同理, 在JavaScriptCore这个框架里, 同样有一个充当桥梁的东西, 那就是JSContext.
在网页加载完毕后, UIWebViewDelegate会回调- (void)webViewDidFinishLoad:(UIWebView *)webView方法, 在这个方法中, 我们可以获取到一个上下文对象:
JSContext *jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
self.jsContext = jsContext;
所有的, 不管是OC端调JS端代码, 还是JS调OC端代码, 都是由JSContext去完成的.
-
JS调用OC代码:
比如要让JS端去打开手机相册.
self.jsContext[@"getImage"] = ^() {
weakSelf.imagePicker = [[UIImagePickerController alloc] init];
weakSelf.imagePicker.delegate = weakSelf;
weakSelf.imagePicker.allowsEditing = YES;
weakSelf.imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[weakSelf presentViewController:weakSelf.imagePicker animated:YES completion:nil];
};
类似于WebViewJavascriptBridge框架的注册方法, OC端先注册这个方法, 把这个block通过KVC的方式保存到上下文中. JS端就通过方法名, 从上下文中取出这个block执行
除了可以调用方法, 还可以通过JS去操作OC对象.
这里的OC对象是遵守JSExport协议的
JSExport有这样一个宏: JSExportAs, 通过这个宏我们可以简化对象方法, 使之更适合JS调用
@protocol PersonProtocol <JSExport>
JSExportAs(show, -(void)showA:(NSString *)a andB:(NSString *)b);
@end
@interface Person : NSObject <PersonProtocol>
@end
在OC中, 我只要将person对象进行注册, 那么在JS中, 我就可以随意使用这个对象, 调用这个对象的方法了:
OC端注册:
Person *p = [Person new];
self.jsContext[@"person"] = p;
JS端调用:
person.show('你好', '我是Martin');
这里实际上调用的就是OC端的代码:
#import "Person.h"
@implementation Person
-(void)showA:(NSString *)a andB:(NSString *)b {
NSLog(@"%s====%@", __func__, [NSString stringWithFormat:@"%@,%@", a, b]);
}
@end
除此之外, 这个框架还为我们提供了异常处理的方法:
self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception) {
context.exception = exception;
NSLog(@"exception == %@",exception);
NSLog(@"%@",context);
};
-
OC调用JS代码
有两种方法:
- 第一种方法是用上下文对象去调用
evaluateScript:方法, 这个在WebKit框架中是用webView对象去调的
2.第二种方法是
[[JSContext currentContext][@"ocCalljs"] callWithArguments:@[@"arg"]];
在用当前上下文去找这个JS方法并调用, callWithArguments:还可以给JS方法传参数.
以上就是我对OC和JS交互的几个框架简单总结, 才疏学浅, 欢迎指正.









