h5页面调用原生app方法

657 阅读2分钟
一、背景以及实现介绍
为了使H5能够调用原生提供的方法,在H5页面的window对象上注入一个JavaScript可以访问到的对象WebBridge。
bridge.js已经做好了封装。
1H5调用原生方法:
hxWebBridge.handlerJSMessage(arg1, arg2)
参数arg1:
json格式的字符串:{"Method":”callScan", "Data”:{}}
arg2:
表示回调方法的名称,假设是:CB_1521683233444_3
2、原生回调H5window.CB_1521683233444_3(null, json对象)
json对象结构约定如下:
{"Method”:”CB_1521683233444_3", "result”:{“url”:”"}}

二、使用方式举例
引入bridge.js文件,调用方式如下:
window.webBridge.callHandler('callScan', null, function (errMsg, res) {
      if (errMsg !== null && errMsg !== 'undefined' && errMsg !== 'null') {
        return reject('service no result back');
      } else {
        return resolve(res);
      }
    });

将brige.js导入main.js中

附bridge.js

(function (win) {
  var ua = navigator.userAgent;

  function getQueryString(name) {
    var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
    var r = window.location.search.substr(1).match(reg);
    if (r !== null) return unescape(r[2]);
    return null;
  }

  function isAndroid() {
    return ua.indexOf('Android') > 0;
  }

  function isIOS() {
    return isIosWKWebView() || /(iPhone|iPad|iPod)/i.test(ua);
  }

  function isIosWKWebView() {
    return (
      !!win.webkit &&
      !!win.webkit.messageHandlers &&
      !!win.webkit.messageHandlers.hxWebBridge
    )
  }

  // invoke callbaks
  const callbacks = {}
  let callbackIndex = 0

  var messageHandlers = {};

  var mobile = {

    /**
     *通过bridge调用app端的方法(异步)
     * @param method
     * @param params
     * @param callback function(err, result)函数
     */
    callHandler: function (method, params, callback) {
      if (!isIosWKWebView() && (!win.hxWebBridge || !win.hxWebBridge.handlerJSMessage)) {
        return false;
      }
      var req = {
        'Method': method,
        'Data': params
      };
      if (isIOS()) {
        if (isIosWKWebView()) {
          const callbackId = ++callbackIndex
          callbacks[callbackId] = callback
          win.webkit.messageHandlers.hxWebBridge.postMessage({
            Method: method,
            Data: params,
            callbackId: callbackId
          })
        } else {
          win.hxWebBridge.handlerJSMessage(req, function (err, result) {
            var resultObj = null;
            var errorMsg = null;
            if (typeof (result) !== 'undefined' && result !== 'null' && result !== null) {
              resultObj = JSON.parse(result);
              if (resultObj) {
                resultObj = resultObj['result'];
              }
            }
            if (err !== 'null' && typeof (err) !== 'undefined' && err !== null) {
              errorMsg = err;
            }
            callback(err, resultObj);
          });
        }
      } else if (isAndroid()) {
        // 生成回调函数方法名称
        var cbName = 'CB_' + Date.now() + '_' + Math.ceil(Math.random() * 10);
        // 挂载一个临时函数到window变量上,方便app回调
        win[cbName] = function (err, result) {
          var resultObj;
          if (typeof (result) !== 'undefined' && result !== null) {
            resultObj = JSON.parse(result)['result'];
          }
          callback(err, resultObj);
          // 回调成功之后删除挂载到window上的临时函数
          delete win[cbName];
        };

        win.hxWebBridge.handlerJSMessage(JSON.stringify(req), cbName);
      }
    },
    /**
     *通过bridge调用app端的方法(同步)
     * @param method
     * @param params
     */
    callHandlerSync: function (method, params) {
      if (!isIosWKWebView() && (!win.hxWebBridge || !win.hxWebBridge.handlerJSMessage)) {
        return false;
      }
      var req = {
        'Method': method,
        'Data': params
      };
      var returnVal = {};
      if (isIOS()) {
        if (isIosWKWebView()) {
          returnVal = prompt("handlerJSMessage", JSON.stringify(req));
          if (returnVal && returnVal !== 'null' && typeof (returnVal) === "string") {
            returnVal = JSON.parse(returnVal);
          }
        } else {
          returnVal = win.hxWebBridge.handlerJSMessageSync(req);
          if (returnVal && returnVal !== 'null' && typeof (returnVal) === "string") {
            returnVal = JSON.parse(returnVal);
          }
        }
      } else if (isAndroid()) {
        returnVal = prompt("handlerJSMessage", JSON.stringify(req));
        if (returnVal && returnVal !== 'null' && typeof (returnVal) === "string") {
          returnVal = JSON.parse(returnVal);
        }
      }
      return returnVal;
    },

    // iOS WKWebView时,当H5调用原生方法时,不能传匿名函数到原生,所有原生实现功能后需要调用此方法回调
    handlerJSMessageCallbackHandler: function (callbackId, params) {
      const callback = callbacks[callbackId];
      if (typeof callback === 'function') {
        var err = params['errMsg'];
        var result = params['result'];
        var resultObj = null;
        if (typeof (result) !== 'undefined' && result !== 'null' && result !== null) {
          resultObj = JSON.parse(result);
        }
        callback(err, resultObj);
      }
    },

    /**
     *通过bridge来handler app端调用的方法
     * @param method
     * @param handler function(params, function(err, result))函数
     */
    registerHandler: function (method, handler) {
      messageHandlers.method = handler;
    },
    /**
     *私有方法,只会在native端调用
     */
    handlerNativeMessage: function (params) {
      var method = params['Method'];
      var data = params['Data'];
      var handler = messageHandlers.method;
      var responseCallback = function (err, result) {
        var response = {};
        response['Method'] = method;
        response['err'] = err;
        response['result'] = result;
        if (isIosWKWebView()) {
          prompt("jsResponseCallback", JSON.stringify(response));
        } else {
          window.hxWebBridge.jsResponseCallback(JSON.stringify(response));
        }
      };
      if (handler != null) {
        handler(data, responseCallback);
      } else {
        responseCallback('JS Method not found', null);
      }
    }
  };
  // 将mobile对象挂载到window全局
  win.webBridge = mobile;
})(window);