1.JSBridge介绍
JSBridge 简单来讲,主要是 给 JavaScript 提供调用 Native 功能的接口,让混合开发中的『前端部分』可以方便地使用地址位置、摄像头甚至支付等 Native 功能。
既然是『简单来讲』,那么 JSBridge 的用途肯定不只『调用 Native 功能』这么简单宽泛。实际上,JSBridge 就像其名称中的『Bridge』的意义一样,是 Native 和非 Native 之间的桥梁,它的核心是 构建 Native 和非 Native 间消息通信的通道,而且是 双向通信的通道。
所谓双向通信的通道:
JS 向 Native 发送消息 : 调用相关功能、通知 Native 当前 JS 的相关状态等。
Native 向 JS 发送消息 : 回溯调用结果、消息推送、通知 JS 当前 Native 的状态等。
1.1 JavaScript 调用 Native
JavaScript 调用 Native 的方式,主要有两种:注入 API 和 拦截 URL SCHEME。
1.1.1注入 API
主要原理是,通过 WebView 提供的接口,向 JavaScript 的 window对象中注入对象或者方法,让 JavaScript 调用时,直接执行相应的 Native 代码逻辑,达到 JavaScript 调用 Native 的目的。
JavaScript可直接通过调用window对象下的对象或者方法,调用Native的相关接口。例如,旧版的掌通家园客户端,通过全局注册seebaby对象,js可以这么调用客户端:window.seebaby.getUserInfo(),
更多示例参考:3.4 客户端与H5交互协议(o2o新增)
1.1.2拦截 URL SCHEME
先解释一下 URL SCHEME:URL SCHEME是一种类似于url的链接,是为了方便app直接互相调用设计的,形式和普通的 url 近似,例如:
ztjy://eyJjYWxsIjoibG9naW4iLCJhcmdzIjp7InR5cGUiOiIwIn19(格式:
发起这样一个网络请求有两种方式:
1. 通过localtion.href;
2. 通过iframe方式;
通过location.href有个问题,就是如果我们连续多次修改window.location.href的值,在Native层只能接收到最后一次请求,前面的请求都会被忽略掉。
使用iframe方式,简单的封闭如下:
var url = 'ztjy://eyJjYWxsIjoibG9naW4iLCJhcmdzIjp7InR5cGUiOiIwIn19';
var iframe = document.createElement('iframe');
iframe.style.width = 0;
iframe.style.height = 0;
iframe.style.display = 'none';
iframe.src = url;
document.body.appendChild(iframe);
setTimeout(function() {
iframe.remove();
}, 100);
拦截 URL SCHEME 的主要流程是:Web 端通过某种方式(例如 iframe.src)发送 URL Scheme 请求,之后 Native 拦截到请求并根据 URL SCHEME(包括所带的参数)进行相关操作。
在时间过程中,这种方式有一定的 缺陷:
使用 iframe.src 发送 URL SCHEME 会有 url 长度的隐患。
创建请求,需要一定的耗时,比注入 API 的方式调用同样的功能,耗时会较长。
但是之前为什么很多方案使用这种方式呢?因为它 支持 iOS6。而现在的大环境下,iOS6 占比很小,基本上可以忽略,所以并不推荐为了 iOS6 使用这种 并不优雅 的方式。
1.2 Native 调用 JavaScript
相比于 JavaScript 调用 Native, Native 调用 JavaScript 较为简单,毕竟不管是 iOS 的 UIWebView 还是 WKWebView,还是 Android 的 WebView 组件,都以子组件的形式存在于 View/Activity 中,直接调用相应的 API 即可。
Native 调用 JavaScript,其实就是执行拼接 JavaScript 字符串,从外部调用 JavaScript 中的方法,因此 JavaScript 的方法必须在全局的 window 上。
以统计页面停留时长为例:
window.onEnter = function (startTime) {
// handler
}
window.onLeave = function (endTime) {
// handler
}
2.Dsbridge
三端易用的现代跨平台 Javascript bridge, 通过它,你可以在Javascript和原生之间同步或异步的调用彼此的函数。
DSBridge的设计原则就是:让三端使用方式都是最简单的!
主要特点:
- Android、IOS、Javascript 三端易用,轻量且强大、安全且健壮。
- 同时支持同步调用和异步调用
- 支持以类的方式集中统一管理API
- 支持API命名空间
- 支持调试模式
- 支持API存在性检测
- 支持进度回调:一次调用,多次返回
- 支持Javascript关闭页面事件回调
- Android端支持腾讯X5内核
假设Native端实现了两个api: testSyn、testAsyn。参数以json传递, testSyn为同步api,执行结束后会直接返回结果,而testAsyn为一个异步api(可能会执行耗时操作),执行结束后,结果异步返回,同时注册一个function,供Native端调用。下面我们看看web端如何调用。
//同步调用
var str=dsBridge.call("testSyn",{msg: "testSyn"});
//异步调用
dsBridge.call("testAsyn",{msg: "testAsyn"}, function (v) {
alert(v);
})
//注册 javascript API
dsBridge.register('addValue',function(l,r){
return l+r;
})
2.1JavaScript调用Native
dsBridge.call(method,[arg,callback])
同步或异步的调用Native API。
method
: Native API 名称, 可以包含命名空间。
arg
:传递给Native API 的参数。只能传一个,如果需要多个参数时,可以合并成一个json对象参数。
callback(String returnValue)
: 处理Native API的返回结果. 可选参数,只有异步调用时才需要提供。
2.2注册JavaScript api供Native调用
2.2.1注册一个普通的方法
同步
dsBridge.register(methodName|namespace,function|synApiObject)
异步
dsBridge.registerAsyn(methodName|namespace,function|asyApiObject)
dsBridge.register('addValue',function(l,r){
return l+r;
})
dsBridge.registerAsyn('addValue',function(arg1,arg2,arg3,responseCallback){
responseCallback(arg1+" "+arg2+" "+arg3);
})
2.2.2注册一个对象,指定一个命名空间
//namespace test for synchronous
dsBridge.register("test",{
tag:"test",
test1:function(){
return this.tag+"1"
},
test2:function(){
return this.tag+"2"
}
})
//namespace test1 for asynchronous calls
dsBridge.registerAsyn("test1",{
tag:"test1",
test1:function(responseCallback){
return responseCallback(this.tag+"1")
},
test2:function(responseCallback){
return responseCallback(this.tag+"2")
}
})
3.实际应用
1.获取命名空间(同步)
const namespace = dsbridge.call(``'getNameSpace'``)
2.获取用户信息
try {
dsbridge.call(namespace + '.getUserInfo', '', val => {
// 回调
})
} catch (e) {}
3.跳转:jumpTo
try {
dsbridge.call(namespace + '.jumpTo', params, val => {
// 回调
})
} catch (e) {}
4.注册刷新回调方法,供客户端调用
dsbridge.register(namespace + '.autoRefreshCallback', () => {
// 回调
})