常见的 JSBridge 设计
LiuuY
LiuuY
JSBridge 是指用于 JavaScript 和原生平台通信的代码。
常见的例如手机 App 中 WebView 的网页需要调用手机的原生能力(例如,从手机获取用户信息)。
通信就包含向原生发送数据,和接收原生发回的数据。
向原生发送数据
对于 Android 平台,会在 WebView 创建的时候定义中的全局 window
对象挂载一个 android 对象成员方法供 JavaScript 调用。
例如:window.android.__CallNative(toNativeData)
,这个 __CallNative
就是 Android 原生在 WebView 创建的时候定义的方法,JavaScript可以直接使用:
// 向原生发送数据
window.android.__CallNative('what is my name?');
对于 iOS 平台,同样的道理,是 window.webkit.messageHandlers.__CallNative.postMessage(toNativeData);
// 向原生发送数据
window.webkit.messageHandlers.__CallNative.postMessage('what is my name?');
需要注意的是,向原生发送数据必须序列化。
接收原生发回的数据
接收原生发回的数据就更加简单粗暴,原生会直接调用一个提前约定好的方法,并将返回的数据作为参数,例如,当原生平台发回的数据的时候,提前定义的 window.__NativeCallback
就会被调用:
// 如果我们定义这个方法,当原生平台发回的数据的时候,data 就会打印出来。
window.__NativeCallback = (data) => {
console.log(data);
}
问题
- 由于返回数据并不是同步的,当需要向原生发送的数据种类繁多时,这种方式难以管理:
// fn1 和 fn2 都向原生请求当前的时间,由于返回数据并非同步,无法区分返回数据对应哪个方法调用。
function fn1() {
window.android.__CallNative(JSON.stringify({type: 'GET_CURRENT_TIME'}));
}
function fn2() {
window.android.__CallNative(JSON.stringify({type: 'GET_CURRENT_TIME'}));
}
window.__NativeCallback = (data) => {
console.log(data);
}
- 现有方式将发送与接收分开为两个全局方法,使用困难,不够简洁。本质上,对于开发者来说,从原生获取数据,和从服务器获取数据都是「异步」,应该将其逻辑统一,例如:
function main() {
JSBridge.getCurrentTime()
.then((data) => {
console.log(data)
}).
catch((error) => {
console.log(error)
})
}
这样与一般的服务端 API 调用习惯无二。
方案
https://github.com/LiuuY/jsbridge
封装了上述逻辑,所有调用返回都是 Promise,对于使用者来说,就与普通异步函数调用无异,😄。
class JSBridgeDemo extends JSBridgeBase {
constructor() {
super();
}
public demoAPI() {
return this.handlePublicAPI('DemoActionID');
}
}
function test() {
const jsBridge = new JSBridgeDemo();
jsBridge.demoAPI()
.then(data => console.log(data))
.error(error => console.log(error))
}