h5和native通信

构建JsBridge,基于客户端webview提供对应交互框架,目前仅提供h5端的使用。

/**
 *  JsBridge 提供和native通信的桥接功能
 */
const JsBridge = function () {
    this.bridge = null // 桥接对象
    this.platform = getPlatform() // 当前客户端平台

    this.init()
}

/**
 * 获取客户端平台类型
 */
function getPlatform() {
  var userAgent = navigator.userAgent.toLowerCase()
  var name = 'Unknown'
  if (userAgent.indexOf('win') > -1) {
    name = 'Windows'
  } else if (userAgent.indexOf('iphone') > -1) {
    name = 'Ios'
  } else if (userAgent.indexOf('mac') > -1) {
    name = 'Mac'
  } else if (userAgent.indexOf('x11') > -1 || userAgent.indexOf('unix') > -1 || userAgent.indexOf('sunname') > -1 || userAgent.indexOf('bsd') > -1) {
    name = 'Unix'
  } else if (userAgent.indexOf('linux') > -1) {
    if (userAgent.indexOf('android') > -1) {
      name = 'Android'
    } else {
      name = 'Linux'
    }
  } else {
    name = 'Unknown'
  }
  return name
}

/**
  * log 将日志输出到dom上
  * @param {string} message 
  * @param {*} data 
  */
function log(message, data) {
  var log = document.getElementById('log')
  if (log) {
    var el = document.createElement('div')
    el.className = 'logLine'
    el.innerHTML = message + ':====== ' + JSON.stringify(data) + ' ======'
    if (log.children.length) { log.insertBefore(el, log.children[0]) } else { log.appendChild(el) }
  } else {
    console.log(message + ':====== ' + JSON.stringify(data) + ' ======')
  }
}

var fn = JsBridge.fn = JsBridge.prototype

/**
 * 初始化bridge
 * @param {Function} done
 */
fn.init = function (done) {
    if (this.platform === 'Ios') {
        this.setupIosWebViewJavascriptBridge(bridge => {
            if (bridge) {
                this.bridge = bridge
                this.registerHandler()
                log('init msg', 'bridge实例挂载成功')
                // bridge初始化有延迟
                setTimeout(() => done && done(bridge), 500)
            } else log('init msg', 'bridge实例挂载失败')
        })
    }
    else if (this.platform === 'Android') {
        this.setupAndroidWebViewJavascriptBridge(bridge => {
            if (bridge) {
                this.bridge = bridge
                log('init msg', 'bridge实例挂载成功')
                // bridge初始化有延迟
                setTimeout(() => done && done(bridge), 500)
            } else log('init msg', 'bridge实例挂载失败')
        })
    }
}

/**
 * JSBRIDGEH5端注册事件
 */
fn.registerHandler = function () {
    log('registerHandler msg', 'JSBRIDGEH5端注册事件')
    this.bridge.registerHandler('testJavascriptHandler', function (data, responseCallBack) {
        log('registerHandler msg', data)
        responseCallBack && responseCallBack(data)
    })
}

/**
 * Android 接入方式
 */
fn.setupAndroidWebViewJavascriptBridge = function (callback) {
    var bridge = window.WebViewJavascriptBridge || window.WKWebViewJavascriptBridge;
    if (bridge) { return callback(bridge); }
    var callbacks = window.WVJBCallbacks || window.WKWVJBCallbacks;
    if (callbacks) { return callbacks.push(callback); }
    window.WVJBCallbacks = window.WKWVJBCallbacks = [callback];
    if (window.WKWebViewJavascriptBridge) {
        window.webkit.messageHandlers.iOS_Native_InjectJavascript.postMessage(null);
    } else {
        var WVJBIframe = document.createElement('iframe');
        WVJBIframe.style.display = 'none';
        WVJBIframe.src = 'https://__bridge_loaded__';
        document.documentElement.appendChild(WVJBIframe);
        setTimeout(function () { document.documentElement.removeChild(WVJBIframe) }, 0);
    }
}

/**
 * Ios jsBridge 接入方式
 */
fn.setupIosWebViewJavascriptBridge = function (callback) {
    if (window.WebViewJavascriptBridge) {
        return callback(window.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)
}

/**
 * 调用bridge公用方法
 * @param {string} eventName 事件名
 * @param {object} data 参数
 * @param {Function} done 回调
 */
fn.callHandler = function (eventName, data = {}, done) {
    try {
        const callFn = (bridge) => {
            bridge.callHandler(eventName, data, function (responseData) {
                log(eventName, responseData)
                done && done(responseData)
            })
        }
        if (!this.bridge) {
            log(eventName, 'JsBridge未初始化')
            this.init(callFn)
            return
        }
        callFn(this.bridge)
    } catch (error) { log(eventName, error) }
}

export default JsBridge

你可能感兴趣的:(h5和native通信)