美文网首页
OC和JS交互的几个框架简单使用

OC和JS交互的几个框架简单使用

作者: 小冰山口 | 来源:发表于2019-05-02 14:53 被阅读0次

本人有若干成套学习视频, 可试看! 可试看! 可试看, 重要的事情说三遍 包含Java, 数据结构与算法, iOS, 安卓, python, flutter等等, 如有需要, 联系微信tsaievan.

<一>WebViewJavascriptBridge

WebViewJavascriptBridge是一套在UIWebViewWKWebView上都可以兼容的与JS交互的框架

OCJS交互无非就是两种情况:

  • OC调用JS方法
  • JS调用OC方法

在这套框架中, 作者巧妙地设计了bridge这个对象, 相当于将OCJS两端用桥连接了起来, bridge这个对象是两端共有的, 不管是在OC的代码中, 还是JS代码中, bridge指针都指向同一个对象

如下图所示:


WebViewJavascriptBridge中JS和OC的交互
那么当我OC端去调JS端方法时, 这个方法首先要在JS端注册.

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

WebViewJavascriptBridge的Demo截图

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的方法呢?
WebViewJavascriptBridge的Demo截图

同理, 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端代码, 还是JSOC端代码, 都是由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代码
    有两种方法:
  1. 第一种方法是用上下文对象去调用evaluateScript:方法, 这个在WebKit框架中是用webView对象去调的
    2.第二种方法是
 [[JSContext currentContext][@"ocCalljs"] callWithArguments:@[@"arg"]];

在用当前上下文去找这个JS方法并调用, callWithArguments:还可以给JS方法传参数.

以上就是我对OCJS交互的几个框架简单总结, 才疏学浅, 欢迎指正.

PS. 本人有若干成套学习视频, 包含Java, 数据结构与算法, iOS, 安卓, python, flutter等等, 如有需要, 联系微信tsaievan.

相关文章

网友评论

      本文标题:OC和JS交互的几个框架简单使用

      本文链接:https://www.haomeiwen.com/subject/kisnnqtx.html