ios与安卓方法兼容(调用客户端方法、客户端调用h5方法)

199 阅读1分钟

main.js

new vue({
    el: "#app",
    router,
    components: {
       App
    },
    template: "<App/>",
      created() { 
        (function() {
          if (window.WebViewJavascriptBridge) {
              return;
          }

          var messagingIframe;
          var sendMessageQueue = [];
          var receiveMessageQueue = [];
          var messageHandlers = {};

          var CUSTOM_PROTOCOL_SCHEME = 'yy';
          var QUEUE_HAS_MESSAGE = '__QUEUE_MESSAGE__/';

          var responseCallbacks = {};
          var uniqueId = 1;

          function _createQueueReadyIframe(doc) {
              messagingIframe = doc.createElement('iframe');
              messagingIframe.style.display = 'none';
              doc.documentElement.appendChild(messagingIframe);
          }

          //set default messageHandler
          function init(messageHandler) {
              if (WebViewJavascriptBridge._messageHandler) {
                  throw new Error('WebViewJavascriptBridge.init called twice');
              }
              WebViewJavascriptBridge._messageHandler = messageHandler;
              var receivedMessages = receiveMessageQueue;
              receiveMessageQueue = null;
              for (var i = 0; i < receivedMessages.length; i++) {
                  _dispatchMessageFromNative(receivedMessages[i]);
              }
          }

          function send(data, responseCallback) {
              _doSend({
                  data: data
              }, responseCallback);
          }

          function registerHandler(handlerName, handler) {
              messageHandlers[handlerName] = handler;
          }

          function callHandler(handlerName, data, responseCallback) {
              _doSend({
                  handlerName: handlerName,
                  data: data
              }, responseCallback);
          }

          //sendMessage add message, 触发native处理 sendMessage
          function _doSend(message, responseCallback) {
              if (responseCallback) {
                  var callbackId = 'cb_' + (uniqueId++) + '_' + new Date().getTime();
                  responseCallbacks[callbackId] = responseCallback;
                  message.callbackId = callbackId;
              }

              sendMessageQueue.push(message);
              messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE;
          }

          // 提供给native调用,该函数作用:获取sendMessageQueue返回给native,由于android不能直接获取返回的内容,所以使用url shouldOverrideUrlLoading 的方式返回内容
          function _fetchQueue() {
              var messageQueueString = JSON.stringify(sendMessageQueue);
              sendMessageQueue = [];
              //android can't read directly the return data, so we can reload iframe src to communicate with java
              messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://return/_fetchQueue/' + encodeURIComponent(messageQueueString);
          }

          //提供给native使用,
          function _dispatchMessageFromNative(messageJSON) {
              setTimeout(function() {
                  var message = JSON.parse(messageJSON);
                  var responseCallback;
                  //java call finished, now need to call js callback function
                  if (message.responseId) {
                      responseCallback = responseCallbacks[message.responseId];
                      if (!responseCallback) {
                          return;
                      }
                      responseCallback(message.responseData);
                      delete responseCallbacks[message.responseId];
                  } else {
                      //直接发送
                      if (message.callbackId) {
                          var callbackResponseId = message.callbackId;
                          responseCallback = function(responseData) {
                              _doSend({
                                  responseId: callbackResponseId,
                                  responseData: responseData
                              });
                          };
                      }

                      var handler = WebViewJavascriptBridge._messageHandler;
                      if (message.handlerName) {
                          handler = messageHandlers[message.handlerName];
                      }
                      //查找指定handler
                      try {
                          handler(message.data, responseCallback);
                      } catch (exception) {
                          if (typeof console != 'undefined') {
                              console.log("WebViewJavascriptBridge: WARNING: javascript handler threw.", message, exception);
                          }
                      }
                  }
              });
          }

          //提供给native调用,receiveMessageQueue 在会在页面加载完后赋值为null,所以
          function _handleMessageFromNative(messageJSON) {
              // console.log(messageJSON);
              if (receiveMessageQueue && receiveMessageQueue.length > 0) {
                  receiveMessageQueue.push(messageJSON);
              } else {
                  _dispatchMessageFromNative(messageJSON);
              }
          }

           var WebViewJavascriptBridge = window.WebViewJavascriptBridge = {
              init: init,
              send: send,
              registerHandler: registerHandler,
              callHandler: callHandler,
              _fetchQueue: _fetchQueue,
              _handleMessageFromNative: _handleMessageFromNative
          };

          var doc = document;
          _createQueueReadyIframe(doc);
          var readyEvent = doc.createEvent('Events');
          readyEvent.initEvent('WebViewJavascriptBridgeReady');
          readyEvent.bridge = WebViewJavascriptBridge;
          doc.dispatchEvent(readyEvent);
      })();
         //用于和APP的原生方法交互(在H5的项目中主要调用isapp的方法判定是否在APP中来判断是否显示导航栏)
         let isAndroid = navigator.userAgent.indexOf('Android') > -1 || navigator.userAgent.indexOf('Adr') > -1;
         let isiOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);

         //Android
        function androidWebView(data) {
          let result = null;
          let name = data.name;
          let callback = () => { };

          if (('data' in data)) {
            if(data.data instanceof Array){
              // console.log(data.data)
              result = window.control[name](...data.data);
            } else {
              let _data = 'type' in data ? data.data :data.data ? JSON.stringify(data.data) : '';
              // console.log(_data)
              result = window.control[name](_data);
              // console.log(result)
            }
          } else {
            result = window.control[name]();
          }
          if(('callback' in data)){
            callback = data.callback;
          }
          callback(result);
        }
         // ios
         function iosWebView(callback,data) {
           if (window.WKWebViewJavascriptBridge) {return callback(window.WKWebViewJavascriptBridge); }
           if (window.WKWVJBCallbacks) {return window.WKWVJBCallbacks.push(callback); }
           window.WKWVJBCallbacks = [callback];
           window.webkit.messageHandlers.iOS_Native_InjectJavascript.postMessage(null)
         }

        function callH(data) {
          if (isiOS) {
             iosWebView(function (bridge) {
               let _data = "";
               if('data' in data && data.data instanceof Array){
                 if(data.data.length > 0){
                   _data = "";
                   data.data.map(item=>{
                     _data += item + ','
                   })
                 }
                 data.data = _data;
               }
               if(!('callback' in data)){
                 data.callback = ()=>{};
               }
               bridge.callHandler(data.name, {'data':data.data}, data.callback)
             })
           } else {
             androidWebView(data)
           }
         };

         // APP调js方法 (参数分别为:js提供的方法名  回调)
         function registerH(name, callback) {
           if (isiOS) {
             iosWebView(function (bridge) {
               bridge.registerHandler(name, function (data, responseCallback) {
                 callback(data, responseCallback({'Javascript Says':'Right back atcha!'}))
               })
             })
           } else {
             window[name] = callback;
           }
         }
         window.callH = callH;
         window.registerH = registerH;
      }
})

使用方式:

调用客户端的方法:

     //  例如将客户端解密后的数据绑定到自己定义的属性上
     callH({
            name: '客户端解密方法',
            data: resp.data.data, //传给客户端的数据
            callback: (res) => { //res为解密方法解密后返回的数据
               resp.data.real = JSON.parse(res);
            }
          })

客户端调用h5的方法(比如跳转某个页面),必须在一进入页面注册方法

mounted(){
    registerH("协商好的方法名(H5自己定义)", this.方法名字)
},
methods: {
  方法名() {
      this.$router.push("/路由");
    },
}