iOS之OC与JS交互(WebViewJavascriptBridge)

前言

最近项目开发中用到了OC与JS交互方面的知识,以前也用过UIWebView JS与OC交互方面的,使用的苹果在iOS7开放的javascriptCore框架,使用起来挺方便快捷,javascriptCore源码是开放的,有兴趣的可以去了解一下。

自从iOS8,苹果就UIWebView性能不好,推出了WKWebView,以及github上评分很高的WebViewJavascriptBridge里面最新版本也最WKWebView做了兼容。

实现的方式

所以我总结的方式,分UIWebview、WKWebView、以及通用版本的第三方WebViewJavascriptBridge,进行实现。

  • UIWebView中JS与OC交互
  • WKWebView中JS与OC交互(只能iOS8及之后的版本)
  • WebViewJavascriptBridge对UIWebView与WKWebView做了同意处理。

WebViewJavascriptBridge

优点

  • UIWebView和WKWebView使用基本相同

  • WebViewJavascriptBridge使用起来方便快捷

  • 安卓版本和iOS版本WebViewJavascriptBridge,实现的JS与原生交互都是一样的,不用针对两个端分别设置不同的代码

基本原理

  • WebViewJavascriptBridge就相当与沟通OC与JS的桥梁。

  • 把 OC 的方法注册到桥梁中,让 JS 去调用。

  • 把 JS 的方法注册在桥梁中,让 OC 去调用。

就是谁注册就是等着被调用,如下图:

iOS之OC与JS交互(WebViewJavascriptBridge)_第1张图片
WebViewJavascriptBridge原理图.png

使用步骤

  • 项目中导入 WebViewJavaScriptBridge 框架
pod ‘WebViewJavascriptBridge’

  • 导入头文件
#import  

  • 初始化WKWebView/UIWebView设置代理

    • 要是UIWebView那就设置UIWebViewDelegate

    • 要是WKWebView那就设置WKNavigationDelegate、WKUIDelegate

代码如下:

//初始化WKWebView
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
webView.navigationDelegate = self;
webView.UIDelegate = self;
[self.view addSubview:webView];

//或者初始化UIWebView
 UIWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
webView.delegate = self;
[self.view addSubview:webView];   
 
  • 给webView建立JS与OjbC的沟通桥梁
 self.bridge = [WebViewJavascriptBridge bridgeForWebView:webView];
[self.bridge setWebViewDelegate:self];

  • OC 注册两个方法,等着JS调用,responseCallback()是返回js的数据,可不传

//registerHandler 注册,等着JS调用 responseCallback是返回js的数据
[self.bridge registerHandler:@"getUserIdFromObjC" handler:^(id data, WVJBResponseCallback responseCallback) {
        
    if (responseCallback) {
    
        responseCallback(@{@"userId":@"123456"});
   }
}];
    
//js调用的这个方法不需要给js反馈数据
[self.bridge registerHandler:@"notReturnFromJS" handler:^(id data, WVJBResponseCallback responseCallback) {
    
    NSLog(@"data -- %@",data);
}];

  • 在clik事件添加OnOCCallJSClick事件,调用JS
- (void) OnOCCallJSClick:(id)sender {
    
    //这种调用js方式,不需要js在给返回值
    [self.bridge callHandler:@"getInfoFromJS" data:@{@"name":@"张三"}];
    
    //callHandler 调用JS  这个方式是,调用js,js有返回值的话,responseData就是js返回的
    [self.bridge callHandler:@"getInfoFromJS" data:@{@"name":@"张三"} responseCallback:^(id responseData) {
        
        
    }];
}

  • 在你需要加载的html中在写上统一的代码,这段代码就能使js与oc建立bridge。
 
    
  • 在JS中也有registerHandler这个方法,注册方法等着OC来调用

  • 在JS中callHandler方法来调用OC方法,

  • JS的responseCallback是OC返回的数据,OC可以不传,responseCallback就为空

注意

如果使用WKWebview来实现WebViewJavascriptBridge,依然存在调用系统的confirm、alert、prompt弹出框被拦截,所以还是要实现UIDelegate代理的三个方法,拦截以后弹出原生的弹出框

#pragma mark - WKUIDelegate

//! alert(message)
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Alert" message:message preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
    }];
    [alertController addAction:cancelAction];
    [self presentViewController:alertController animated:YES completion:nil];
}

//! confirm(message)
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler {
    
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Confirm" message:message preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(NO);
    }];
    UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(YES);
    }];
    [alertController addAction:cancelAction];
    [alertController addAction:confirmAction];
    [self presentViewController:alertController animated:YES completion:nil];
}

//! prompt(prompt, defaultText)
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *))completionHandler {
    
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:prompt message:nil preferredStyle:UIAlertControllerStyleAlert];
    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.placeholder = defaultText;
    }];
    UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(alertController.textFields[0].text);
    }];
    [alertController addAction:confirmAction];
    [self presentViewController:alertController animated:YES completion:nil];
}

结尾

WebViewJavascriptBridge使用起来比较方便快捷,并且还有安卓版本的WebViewJavascriptBridge,所有安卓和iOS都使用的话,就避免了前端既要写一份安卓又要写一份iOS的JS与OC交互,调试起来只要一端通了,JS那边应该就没啥问题,排查问题方便,不用的iOS和安卓会有不同的问题,可能你解决iOS会引起安卓问题,所以统一性比较重要。(如些有不足请批评指正,满意的话给个赞~~~)

你可能感兴趣的:(iOS之OC与JS交互(WebViewJavascriptBridge))