The OC iOS and JS interaction (WebViewJavascriptBridge)

Foreword

Recently used in a project to develop the knowledge OC JS interact with aspects of the previously used UIWebView JS OC interact with aspects of apple used in iOS7 open javascriptCore framework, very convenient to use, javascriptCore source code is open, interested you can go to find out.

Since iOS8, Apple UIWebView performance is not good, we launched WKWebView, and score high on github inside the latest version WebViewJavascriptBridge most WKWebView made compatible.

The way to achieve

So my summary of the way, points UIWebview, WKWebView, and third-party WebViewJavascriptBridge generic versions, were realized.

  • JS OC interaction with the UIWebView
  • WKWebView in JS OC interact with (only iOS8 and later versions)
  • WebViewJavascriptBridge for UIWebView do agree with WKWebView process.

WebViewJavascriptBridge

advantage

  • Using essentially the same and WKWebView UIWebView

  • WebViewJavascriptBridge convenient to use

  • Android version and iOS version WebViewJavascriptBridge, JS native interaction with the realization of the same, no two ends are set for a different code

Fundamental

  • WebViewJavascriptBridge quite a bridge to communicate with the OC and JS.

  • The OC method registered to the bridge, so that JS to call.

  • The method of registration in JS bridge, so that OC to call.

Who is registered is waiting to be called, as shown below:

15936146-2840fa7dce227602.png
WebViewJavascriptBridge schematics .png

Steps for usage

  • Import WebViewJavaScriptBridge project framework
pod ‘WebViewJavascriptBridge’

  • Import header file
#import <WebViewJavascriptBridge.h> 

  • Initialization WKWebView / UIWebView proxy settings

    • If it is set UIWebView UIWebViewDelegate

    • If WKWebView then set WKNavigationDelegate, WKUIDelegate

code show as below:

//初始化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];   
 
  • Build a bridge between JS and OjbC to webView
 self.bridge = [WebViewJavascriptBridge bridgeForWebView:webView];
[self.bridge setWebViewDelegate:self];

  • OC register two methods, JS call waiting, responseCallback () return js data may not pass

//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);
}];

  • Add OnOCCallJSClick event clik event, call the 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) {
        
        
    }];
}

  • You need to load html in the <script> </ script> write uniform code, which can make the oc js build bridge.
 <script>
      window.onerror = function(err) {
        log('window.onerror: ' + err)
      }
    
      /*这段代码是固定的,必须要放到js中*/
      function setupWebViewJavascriptBridge(callback) {
        if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
        if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
        window.WVJBCallbacks = [callback];
        var WVJBIframe = document.createElement('iframe');
        WVJBIframe.style.display = 'none';
        WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
        document.documentElement.appendChild(WVJBIframe);
        setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
      }
    
      /*与OC交互的所有JS方法都要放在此处注册,才能调用通过JS调用OC或者让OC调用这里的JS*/
      setupWebViewJavascriptBridge(function(bridge) {
       var uniqueId = 1
       function log(message, data) {
         var log = document.getElementById('log')
         var el = document.createElement('div')
         el.className = 'logLine'
         el.innerHTML = uniqueId++ + '. ' + message + ':<br/>' + JSON.stringify(data)
         if (log.children.length) {
            log.insertBefore(el, log.children[0])
         } else {
           log.appendChild(el)
         }
       }
       
       /* Initialize your app here */
       
       /*我们在这注册一个js调用OC的方法,不带参数,
        *且不用ObjC端反馈结果给JS:打开本demo对应的博文
        */
       bridge.registerHandler('openWebviewBridgeArticle', function() {
                              
                              confirm("郭杨和小代是好朋友吗?");
          log("openWebviewBridgeArticle was called with by ObjC")
       })
       
      /*JS给ObjC提供公开的API,在ObjC端可以手动调用JS的这个API。
       *接收ObjC传过来的参数,且可以回调ObjC
       */
       bridge.registerHandler('getUserInfos', function(data, responseCallback) {
         log("Get user information from ObjC: ", data)
         responseCallback({'userId': '123456', 'blog': '标哥的技术博客'})
       })
                                   
      /*JS给ObjC提供公开的API,ObjC端通过注册,就可以在JS端调用此API时,得到回调。
       *ObjC端可以在处理完成后,反馈给JS,这样写就是在载入页面完成时就先调用
       */
    bridge.callHandler('getUserIdFromObjC', function(responseData) {
                    
         log("JS call ObjC's getUserIdFromObjC function, and js received response:", responseData)
       })
       
    })        
</script>
    
  • JS also has registerHandler in this method, registration method to call waiting OC

  • In JS callHandler way to call OC method,

  • The JS responseCallback data is returned OC, OC may not pass, responseCallback is empty

note

If you use WKWebview to achieve WebViewJavascriptBridge, still confirm call system, alert, prompt pop-up box was blocked, so we should implement three methods UIDelegate proxy, pop-pop-up box after intercepting native

#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];
}

end

WebViewJavascriptBridge use more convenient, and there are Android version of WebViewJavascriptBridge, all Android and iOS are used, avoiding both the front-end Android but also to write a written JS OC interaction with an iOS, debug as long as one end of the pass a, JS there should be nothing on the issue, to facilitate troubleshooting, not iOS and Android have different problems that may cause you to solve iOS Andrews problems, so unity is more important. (As some have inadequate please criticism and satisfaction, then give a praise ~ ~ ~)

Guess you like

Origin blog.csdn.net/weixin_34408717/article/details/90932309