Jsbridge搭建

Posted by Asser's Blog on December 28, 2018

jsBridge 搭建

原理:

  1. native部分在window对象下注入自己的方法, web端通过调用被注入的方法来通知native 从而进行native方法的调用

  2. native接到通知后,调用自己的方法,在调用结束后,再调用window对象的js方法,通知web端。

坑点:

  1. native的注入过程是一个异步操作。有可能在html页面加载完成之后,app端的js注入依旧没有完成!

  2. ios端可以接受直接将object和function作为参数传给native,并且可以直接使用传过来的function,回调通知web。但是安卓端貌似不可以

解决思路:

关于问题1:

方案一:

由于在app端使用vue框架。被native注入成功后再new Vue对象。确保页面内所有的native方法均可以使用.有效避免app注入未完成就直接进行调用的情况

缺陷: 假如app注入js时间过长,页面将会一直呈现空白页面

方案二:

将所有的调用native接口的动作存储在任务队列中,当app注入js成功时广播通知任务队列,将任务队列中全部积攒的任务进行执行

缺陷: 可能存在反复调用native接口的问题

关于问题2:

采用发布订阅模式。h5端调用的native的回调,均存储于window对象下的一个全局变量中 nativeTaskQueue 存储的数据格式如下:

[
    {
        callBackName: 'xxx',
        callBackFns: [fn1, fn2]
    }
]

(订阅者)

native端处理完数据之后,调用暴露在window对象下的发布方法,通知每一个订阅者,根据callBackName调用对应的回调

(发布者)

总结

native端需要注入的方法
window.jsBridge.postMessage({
    methodName: 'callPhone',
    params: 'aabbcc',
    successCallbackName: 'cb_success',
    failureCallBackName: 'cb_error'
}) // 该native可以直接接受Object类型,否则可以考虑转成json传入
h5端需要创建的方法
window.nativeEventHandler = {
    events: [], // 存放native处理完之后的js回调
    
    /*
     * desc: H5端添加调用native方法后执行的回调函数
     * params:
     *  name: (string) 回调函数名称
     *  fn: (function) 对应回调函数
     */
    addCallBack: function(name, fn) {
        if (typeof fn === 'function') {
            this.events.push({
                name: name,
                fn: fn
            })
        } 
    },
    
    /*
     * desc: H5端删除执行完毕的回调函数
     * params: 
     *  index: (int)被删除函数的序列号
     */
    removeEvent: function(index) {
        this.events.splice(index, 1)
    },
    
    /*
     * desc: 原生方法调用结束后分发结果的方法
     * params: 
     *  name: (string) 回调函数名称
     *  data: (string) native方法返回值
     */
    releaseEvents: function(name, data) {
        this.events.forEach((event, index) => {
            if (event.name === name && typeof event.fn === 'function') {
                event.fn(data)
                this.removeEvent(index)
            } 
        })
    },
    
    /*
     *  desc: H5端调用native的方法
     *  params:
     *  {
     *      name: (string) native方法名,
     *      callBackName: (string) js回调名称
     *      params: (object) 需要传给native的参数
     *      success: (function) 原生执行成功之后的回调
     *      error: (function) 原生执行失败之后的回调
     *  }
     */
    callNative: function(params) {
        let successCb = params['callBackName'] ? params['callBackName'] + '_success' : ''
        let errorCb = params['callBackName'] ? params['callBackName'] + '_error' : ''
        window.jsBridge.postMessage({
            methodName: params['name'],
            params: params['params'],
            successCallbackName: successCb,
            failureCallBackName: errorCb
        })
        if (successCb) {
            this.addCallBack(successCb, params['success'])
        } 
        if (errorCb) {
            this.addCallBack(errorCb, params['error'])
        } 
    }
}