# 小程序中JSBridge的实现
# JSBridge的介绍
let jsCore;
/* Android端注入 */
if (self.JSCore) {
jsCore = JSCore;
}
/* iOS端 */
else {
const messageHandlers = self.webkit.messageHandlers;
jsCore = {
call: function(method, paramsString, webviewIdsString, callbackId) {
messageHandlers.BridgeCall.postMessage(method, paramsString, webviewIdsString, callbackId)
},
publish: function(event, paramsString, webviewIdsString) {
messageHandlers.BridgePublish.postMessage(method, paramsString, webviewIdsString)
}
}
}
# 根据小程序特点实现JSBridge
从底层来看小程序和h5唯一的区别,是将视图和逻辑隔离形成了双线程,jsb需要承载线程之间的通信功能,其实就是纯粹的转发能力。
jsb主要可以分为:
调用类:
- 调用native能力[1]
- 调用线程[2] (逻辑层->渲染层、渲染层->逻辑层)
监听类:
- 监听native事件[3]
- 监听线程[4]
回调类:由native执行调用,一般不暴露给使用者
- 调用native能力[1]后的回调
- 监听事件的回调[5],消息包含监听native事件[3]的回调、监听线程[4]的回调
所以简单实现如下:
function createInvoke(jsCore) {
let resolveId = 0; // 调用唯一标识
const resolveMap = new Map();
/* 调用native能力[1] */
function invokeNative(method, params, webviewId) {
let response;
const deferred = new Promise((resolve, reject) => {
resolveId+=1;
resolveMap.set(resolveId, resolve}); // 暂不考虑失败情况
const paramsString = JSON.stringify(params);
const webviewIds = Array.isArray(webviewId) ? webviewId : [webviewId];
const webviewIdsString = JSON.stringify(webviewIds);
response = jsCore.call(method, paramsString, webviewIdsString, resolveId);
})
/* 同步api */
if (response) {
resolveMap.delete(resolveId);
return JSON.parse(response);
}
/* 异步api */
return deferred;
}
/* 调用native能力[1]后的回调 */
function invokeHandler(resolveId, data) {
const resolve = resolveMap.get(Number(resolveId));
if (!resolve) return;
resolve(JSON.parse(data));
}
return {
invokeNative,
invokeHandler
}
}
function createPublish(jsCore) {
/* 调用线程[2] */
const publish = (method, params, webviewId) => {
const paramsString = JSON.stringify(params);
const webviewIds = Array.isArray(webviewId) ? webviewId : [webviewId];
const webviewIdsString = JSON.stringify(webviewIds);
jsCore.publish(`${CUSTOM_EVENT}${method}`, paramsString, webviewIdsString, g.__IS_WORKER__);
};
return {
publish,
};
}
function createSubscribe() {
const nativeEmitter = new EventEmitter();
const customEmitter = new EventEmitter();
return {
/* 监听native事件[3] */
onNative: nativeEmitter.on.bind(nativeEmitter),
offNative: nativeEmitter.off.bind(nativeEmitter),
/* 监听线程[4] */
subscribe(event, listener) {
customEmitter.on.call(customEmitter, `custom_event_${event}`, listener);
},
unsubscribe(event, listener) {
customEmitter.off.call(customEmitter, `custom_event_${event}`, listener);
},
/* 监听事件的回调[5] */
subscribeHandler(event, data, webviewId) {
let params = JSON.parse(data);
if (event.startsWith('custom_event_')) {
customEmitter.emit.call(customEmitter, event, params, webviewId);
} else {
nativeEmitter.emit.call(nativeEmitter, event, params, webviewId);
}
},
};
}
# 总结
所以上面实现后的jsb,对使用者暴露的方法为:
- invokeNative
- onNative
- offNative
- publish
- subscribe
- unsubscribe
invokeHandler和subscribeHandler挂载到全局,供native调用使用。