jsBridge 搭建
原理:
-
native部分在window对象下注入自己的方法, web端通过调用被注入的方法来通知native 从而进行native方法的调用
-
native接到通知后,调用自己的方法,在调用结束后,再调用window对象的js方法,通知web端。
坑点:
-
native的注入过程是一个异步操作。有可能在html页面加载完成之后,app端的js注入依旧没有完成!
-
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'])
}
}
}