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

本人有若干成套学习视频, 可试看! 可试看! 可试看, 重要的事情说三遍 包含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.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,063评论 6 510
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,805评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,403评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,110评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,130评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,877评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,533评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,429评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,947评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,078评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,204评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,894评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,546评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,086评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,195评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,519评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,198评论 2 357

推荐阅读更多精彩内容