JS与OC交互文档(Web端)

 1、iOS系统API交互方式

 1.1、Objective-C调用Javascript方法

   前提

  UIWebView已经完全加载完成包含需要调用的页面(注:在UIWebViewDelegate托管中通过监视- (void)webViewDidFinishLoad:(UIWebView *)webView调用来确定页面是否加载完成)。

      方法

  假设某视图对象的子视图属性self.webview加载的页面包含如下Javascript函数:

  function getString(){ return “Hello javascript!”;}

   并且该函数在该页面上可被正常调用,则可以通过形如下面的Objectvie-C方法调用此函数:

  NSString *str = [self.webview stringByEvaluatingJavaScriptFromString:@“getString()"];

   该函数调用实际模拟了页面上的一次Javascript函数调用,因此在该函数内部任何有效的Javascript代码都可被执行!该Objective-C代码返回值为被调用的Javascript代码的返回值,在上例中,str的值将被赋为@”Hello javascript!”。

   被调用的函数可以带有字符串或数值型的参数。若调用的Javascript函数名称带有参数,需保证传进去的参数的格式正确性,特别是字符串参数的引号很容易被忽略。

1.2、客户端响应页面Javascript代码

  前提:

       需要实现UIWebViewDelegate的- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType托管函数(以下简称跳转监视函数)并将实现了该托管函数的对象设置为UIWebView的delegate。

      方法

       UIWebView的当前页面将要被Javascript代码通过以下方式转向的时候,会调用上述跳转监视函数:

       window.location.href=”http://www.strongsoft.net”;

  此时实现了该托管协议的对象的跳转监视函数会被调用,通过如下代码监视浏览器跳转的地址:

       NSString *url = [[request URL] absoluteString];

  若该托管函数返回值为NO,则页面UIWebView的页面跳转将被否决。利用这一思路,监视页面上的特定格式的跳转地址加以拦截,并执行相应的本地代码,即可实现Javascript与Objective-C代码的交互。

       例如,规定拦截URL地址前缀为”objc:”的所有地址,并且用if…else…语句判定本地需要执行的代码,比如执行doFunc1函数,那么可通过如下Javascript函数进行:

       window.location.href=”objc:doFunc1”;

       此方式实现JS向客户端传递的消息存在于href的字符串中,客户端通过解析字符串提取所需信息。

  

2、引入第三方库WebViewJavascriptBridge进行交互

  WebViewJavascriptBridge优雅地实现了在使用 UIWebView 时 JS 与 iOS 的 OC 之间的互调,支持消息发送、接收、消息处理器的注册与调用以及设置消息处理的回调。 就像项目的名称一样,它是连接UIWebView和Javascript的bridge。在加入这个项目之后,他们之间的交互处理方式变得很友好。

  一起来看看它的实现吧,它总共就包含了三个文件:

  1 WebViewJavascriptBridge.h  

  2 WebViewJavascriptBridge.m  

  3 WebViewJavascriptBridge.js.txt  

  WebViewJavascriptBridge.js.txt 主要用于衔接 UIWebView 中的 web page ,而 WebViewJavascriptBridge.h/m 则主要用于与 OC 的 native code 打交道。他们作为一个整体,其实起到了一个“桥梁”的作用,这三个文件封装了他们具体的交互处理方式,只开放出一些对外的涉及到业务处理的API,因此你在需要UIWebView与Native code交互的时候,引入该库,则无需考虑太多的交互上的问题。

  出于表达上的需要,对于UIWebView相关的我就称之为Web端,而objc那端的处理代码称之为Native端。

  Web端以及Native端完全是对等的两端,实现也是对等的。一段是消息的发送端,另一段就是接收端。这里为引起混淆,需要解释一下我这里使用的“响应”、“回调”在这个上下文中的定义:

  (1)   响应:接收端给予发送端的应答

  (2)   回调:发送端收到接收端的应答之后在接收端调用的处理逻辑

下面罗列一下它可以实现的功能(Web端):

  • Web端在初始化时支持设置消息的默认处理器(这里的消息指的是从Native端接收到的消息)
  •  从Web端向Native端发送消息,并支持对于Native端响应后的回调处理的定义
  •  Web端调用Native定义的处理器,并支持Native端响应后的回调处理定义
  •  Web端注册处理器(供Native端调用),并支持给Native端响应处理逻辑的定义

//给WebViewJavascriptBridgeReady事件注册一个Listener

<span style="white-space:pre">  </span>

document.addEventListener('WebViewJavascriptBridgeReady', onBridgeReady, false)

//事件的响应处理

<span style="white-space:pre">  </span>

function onBridgeReady(event) {  

     var bridge = event.bridge

//初始化操作,并定义默认的消息处理逻辑

<span style="white-space:pre">  </span>

bridge.init(function(message) {  

            log('JS got a message', message)  

       })

//注册一个名为testJavascriptHandler的处理器,并定义用于响应的处理逻辑(该处理器可在native端调用名为testJavascriptHandler的处理器后,进行响应操作) 

<span style="white-space:pre">  </span>

 bridge.registerHandler('testJavascriptHandler', function(data, response) {  

            log('JS handler testJavascriptHandler was called', data)  

            response.respondWith({ 'Javascript Says':'Right back atcha!'  })  

      })

//创建一个发送消息给native端的按钮

<span style="white-space:pre">  </span>  

        var button = document.getElementById('buttons').appendChild(document.createElement('button'))  

        button.innerHTML = 'Send message to ObjC'  

        button.ontouchstart = function(e) {  

             e.preventDefault()  

              <span style="white-space:pre">      </span>//发送消息  

              bridge.send('Hello from JS button')  

        }  

     document.body.appendChild(document.createElement('br'))  

//创建一个用于调用native端处理器的按钮

 <span style="white-space:pre">  </span>  

        var callbackButton = document.getElementById('buttons').appendChild(document.createElement('button'))  

        callbackButton.innerHTML = 'Fire testObjcCallback'  

        callbackButton.ontouchstart = function(e) {  

            e.preventDefault()  

            log("Calling handler testObjcCallback”)

  

            //调用名为testObjcCallback的native端处理器,并传递参数,同时设置回调处理逻辑(与上面对应,客户端也需register一个同样名称的处理器来进行相应响应)  

            bridge.callHandler('testObjcCallback', {'foo': 'bar'}, function(response) {  

                log('Got response from testObjcCallback', response)  

            })  

        }  

    }  

3、iOS 8以上系统的交互

  iOS 8之后引入了WKWebView,客户端有系统API来处理Web端发送过来的消息,Web端需要做的也精简不少,代码如下:

  window.webkit.messageHandlers.testObjcCallbackIniOS8.postMessage({

    "infomation": "someData","

  });

其中,testObjcCallbackIniOS8是Web端调用Native端的处理器的名称,Native端可在相应方法中,进行判断并处理。

五、参考资料

  1. http://zh.5long.me/2015/ios-objective-c-javascript-bridge/    《iOS开发之Objective-C(Swift)与JavaScript交互·WebViewJavascriptBridge使用篇》
  2. http://www.cnblogs.com/YouXianMing/p/3738317.html   《使用WebViewJavascriptBridge与UIWebView交互》
  3. http://blog.csdn.net/yanghua_kobe/article/details/8209751   《优秀开源代码解读之JS与iOS Native Code互调的优雅实现方案》
原文地址:https://www.cnblogs.com/Jacue/p/4961561.html