巅峰对决 DSBridge vs WebViewJavascriptBridge

随着HTML5的不断普及及优化,以及移动端对动态化的需求越来越大,开发者经常需要在app中嵌入一些网页,然后会在web和native之间进行交互,如传递数据,调用函数,而连接web与native需要一个桥梁。DSBridge android 和 ios 版上两篇文章已经介绍完毕,既然DSBridge 号称是地球上最好用的跨平台开源 js bridge,那么今天就将它和现在的老大 WebViewJavascriptBridge 全方位对比一下,看看究竟是初生牛犊不怕虎还是哗众取宠,又或是实至名归......

DSBridge vs WebViewJavascriptBridge

下面是DSBridge和WebViewJavascriptBridge的github地址:

DSBridge-IOS:https://github.com/wendux/DSBridge-IOS
DSBridge-Android:https://github.com/wendux/DSBridge-Android

WebViewJavascriptBridge(ios) https://github.com/marcuswestin/WebViewJavascriptBridge

约定:一下术语“端”指的是native(ios/android), 而 “前端” 特指 web端(javascript);

好桥的标准

  1. 跨平台;这是首要的,必须同时支持ios/android,因为网页会嵌入到端上,而网页代码只有一份,同样的javascript代码必须能同时保证能和ios/android正常通信。
  2. 三端易用;三端指ios 、android和前端。这很重要,因为它会直接影响工作量和代码量。
  3. 双向调用;js可以调用native, native可以调用js;
  4. 支持同步/异步调用;同步用于一般任务,异步主要用于耗时任务,调用方式不同会影响前段代码流程。
  5. 性能、兼容性等。

跨平台

通过github上的信息可以看到DSBridge官方是同时支持ios/android的,但是注意到,DSBridge ios版是支持wkwebview的,而wkwebview也是可以用在osx中,也就是说DSBridge ios版也是可以用于mac开发的。也就是说DSBridge同时支持:ios/android/osx。再来看看WebViewJavascriptBridge,官方说明是支持ios/osx的,但WebViewJavascriptBridge并不支持android, 当然,由于WebViewJavascriptBridge的人气实在太高,也有一些人在android上实现了兼容的版本如这个点我,但是总的来说,并非一家之作,这可能会给日后维护带来问题。而DSBridge是同一个作者,如果将来更新时可以保证双端同步。第一回合,DSBridge胜!

易用性

Javascript Bridge比较特殊,因为它要同时涉及三端,让三个端使用起来都比较容易是很有挑战的一个任务,这不仅是能力层面,也和接口和使用方式的设计息息相关,当然能在三端之间做出最好的平衡,也对作者能力要求比较高(必须同时了解ios/android/web)。 接下来我们分别从三端的接口和使用方式做一个详细对比。

web端

Javascript调用native

假设native有个回显信息的函数,签名如下:

String echo(JSONObject args); //先用java描述

该函数功能是js调用时传递一个字符串msg给端,然后端上再返回 "you put string "+msg; 参数以json传递。

先来看看WebViewJavascriptBridge的调用方式

第一步:复制 setupWebViewJavascriptBridge 函数声明到你的js中:

function setupWebViewJavascriptBridge(callback) {
    if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
    if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
    window.WVJBCallbacks = [callback];
    var WVJBIframe = document.createElement('iframe');
    WVJBIframe.style.display = 'none';
    WVJBIframe.src = 'https://__bridge_loaded__';
    document.documentElement.appendChild(WVJBIframe);
    setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
}

第二步:调用 setupWebViewJavascriptBridge,在回调中获得bridge, 然后通过bridge调用native方法:

setupWebViewJavascriptBridge(function(bridge) {
    bridge.callHandler('echo', {'msg':'hello world'}, function responseCallback(responseData) {
        console.log(responseData)
    })
})

我们再来看看DSBridge的调用方式

var bridge = getJsBridge();
var str=bridge.call("testSyn", {msg: "hello world"});
console.log(str)

甚至只需要一行代码:

console.log(getJsBridge().call("testSyn", {msg: "hello world"}))

对比一下,WebViewJavascriptBridge 的setupWebViewJavascriptBridge函数必须在使用者代码中声明,而此函数主要的作用就是安装bridge,安装成功后,只能在回调中获取bridge对象;这么做有两大缺点:

  1. bridge安装细节不应暴漏给用户;setupWebViewJavascriptBridge不应该由用户声明,这个函数从来都不变,安装的过程应该由sdk去做,这样强制要求用户自己声明调用不仅不符合职责分离的软件设计原则,而且还会造成代码冗余,试想每个网页中都要加这么一块代码,不仅麻烦,而且也浪费带宽。(可能你不在乎用户的流量,但是如果你的用户很多而服务器、带宽资源有限,这对服务器来说也是一个问题,笔者阿里云的ecs带宽只有1兆,而网站就跑了六个,同时在线人数超过200人没人将会感觉到卡,如果你是土豪,那无视这个吧)。
  2. 不能直接获取返回值;这点很重要,只能通过回调方式处理返将直接影响前端代码组织逻辑,将会在后面同步/异步对比部分详细讨论。

然而DSBridge 竟是如此优雅!

Natvie 调用 javascript函数

使用WebViewJavascriptBridge时,提供给native调用js函数必须通过bridge在前端进行注册,如:

setupWebViewJavascriptBridge(function(bridge) {
    bridge.registerHandler('jsfun', function(data, responseCallback) {
        console.log("I am js function, arg is:", data)
        responseCallback(data)
    })
})

而DSBridge中完全不需要,只需像正常函数一样将其声明为全局函数即可:

function jsfun(data){
  console.log("I am js function, arg is:", data)
}

如果你的代码不再全局环境下(在一个闭包中),您只需将函数作为window对象的一个属性即可:

window.jsfun=function(data){
  console.log("I am js function, arg is:", data)
}

第二回合 DSBridge完胜!

IOS端

实现API的方式

WebViewJavascriptBridge需要手动注册所有可供js调用的api,如下:

[self.bridge registerHandler:@"echo" handler:^(id data, WVJBResponseCallback responseCallback) {
   //设置js函数的返回值,该值将在js调用时传递的回调中接收 
   responseCallback(...);
}];
[self.bridge registerHandler:@"api2" handler:^(id data, WVJBResponseCallback responseCallback) {
    responseCallback(...);
}];
...

需要注意的是WebViewJavascriptBridge对返回值的处理只能通过block.

我们看看DSBridge,很简单只需要将所有api放到一个类中,然后统一注册即可,还有返回值可以直接返回

//JsApiTest.m
@implementation JsApiTest
- (NSString *) echo:(NSDictionary *) args
{
    return @"...";
}
- (NSString *) api2:(NSDictionary *) args 
{
   return @"..."; 
}
@end
//统一注册
jsApi=[[JsApiTest alloc] init];
webview.JavascriptInterfaceObject=jsApi;

Android端

android端和ios端类似,我们复制一下https://github.com/gzsll/WebViewJavascriptBridge 下的例子(这是android的一个兼容实现):

webView.registerHandler("api1", new WVJBWebView.WVJBHandler() {
       @Override
       public void request(Object data, WVJBWebView.WVJBResponseCallback callback) {
           callback.callback("return value");
       }
});
webView.registerHandler("api2", new WVJBWebView.WVJBHandler() {
       @Override
       public void request(Object data, WVJBWebView.WVJBResponseCallback callback) {
          callback.callback("return value");
       }
});
...

每个api都要单独注册,我们来看看DSBridge官方给出的例子:

public class JsApi{
    //同步api
    @JavascriptInterface
    String api1(JSONObject jsonObject) throws JSONException {
        return jsonObject.getString("msg") + "[syn call]";
    }
    //异步api
    @JavascriptInterface
    void api2(JSONObject jsonObject, CompletionHandler handler) throws JSONException {
        handler.complete(jsonObject.getString("msg")+" [asyn call]");
    }
}
//注册
webView.setJavascriptInterface(new JsApi());

DSBridge不用每个api都去手动注册,只需要将所有api放到一个类中,将需要供js调用的api添加@JavascriptInterface标注即可(出于安全的考虑,关于这个话题,如果有兴趣可自行google)。

对比一下:

WebViewJavascriptBridge为每个api都要单独注册,并且返回值只能通过block或委托;而DSBridge这种统一注册的方式不仅简洁方便,而且所有api放在同一个类中也有助于代码管理,清晰,优雅;而DSBridge同步api可以直接返回值!

综上所述,无论在前端还是在ios/android,在易用性上 DSBridge完胜WebViewJavascriptBridge。

Native调用js

Native调用js方面,两者差异不大,具体请参考github说明,持平。

支持同步/异步调用支持

这是DSBridge大显神威的主要地方,在比较之前,我们先来讨论一下同步/异步对程序流程的影响:如果你是一名前端开发者,想必对异步、回调这些概念已经有所体会,如果你接触过node, 那应该早已深入骨髓。javascript语言从设计为单线程开始就决定了它将与异步相伴终老的局面。纵观晚上node被黑的所有理由中,“过多依赖异步导致代码流程难以控制”首当其冲,随然 node社区一些非常知名的第三方包,有很多都和异步转同步、流程控制相关,如bluebird、async,fibers等. 甚至最新的ECMA标准中引入的generator/yield 、 Promise、async/await等都和同步/异步有关。javascript最成功的地方是异步然而最受诟病的也是异步,当然,我不打算过多讨论js语言,我们回来,看看过多的异步会带来什么问题,试想如下的需求:

假设有一个内嵌在端上的web功能模块,有多个页面,而多个页面之间需要通过端共享一些数据 ,为了说明问题,我们不使用h5本地存储。假设前端的逻辑需要在不同的时段从端上获取不同的数据,用WebViewJavascriptBridge的话,代码整体的流程大概会是下面这个样子:

bridge.callHandler('getData', {'key':'name'}, function responseCallback(responseData) {
    //执行一些操作
    bridge.callHandler('getData', {'key':'age'}, function responseCallback(responseData) {
        //执行一些操作
        ...
        bridge.callHandler('getData', {'key':'sex'}, function responseCallback(responseData) {
          ...
        })
    })
})

我们来仔细看看这种方式有什么问题,首先,获取数据并非耗时操作,端上的API设计成同步,但是由于WebViewJavascriptBridge前端只支持异步调用方式,所以最终的代码将必然是回调套回调,如果交互变多,这种情况会变的更糟,这就是异步编程最大的缺点,流程难以理解,但人类的思维模式是同步的,第一步做什么,然后第二步做什么,用代码来描述就是第一句执行什么,然后第二句执行什么,然而这种基于回调的方式却正好相反,简单一点的应用,不会有太大问题,但是稍微复杂一点的应用,事情将会变的很糟。

然而,DSBridge让一切变的简单!

我们看看用DSBridge实现上述逻辑的大概样子:

var name=bridge.call('getData', {'key':'name'});
//执行一些操作
var age=bridge.call('getData', {'key':'age'});
//执行一些操作
var sex=bridge.call('getData', {'key':'sex'});

简单清晰!

当然,DSBridge也是支持异步调用的,这通常用于耗时的api调用,调用方式请查看github文档。

到目前为止,据作者所知,跨平台的js bridge中,DSBridge是唯一一个支持同步调用的!这一点吊打包括WebViewJavascriptBridge在内现有的其它几乎所有的js bridge

性能、兼容性

从底层的实现来看,WebViewJavascriptBridge是通过iframe和自定义协议在web和native之间传递数据,属于一种间接的做法,因为在android下,js是可以直接和java对象关联通信的,而在ios下UIWebview可以直接使用JavascriptContext实现和安卓类似的功能:js 可以直接和 oc对象关联,而DSBridge在android和ios、uiwebview中是直接通过js和原生对象关联方式直接通信。具体性能虽没有做过专门测试,当从实现方式上来看,DSBridge少了一个iframe中间层,应该会高一些。

关于兼容性,两者差不多,ios都支持7.0以上,DSBridge理论上支持所有android版本,但是考虑到近年来移动端浏览器对h5支持的快速提高,默认的最低版本设置为api16, 你可以根据自己的需求修改这个配置。

总结

通过各方面对比,DSBridge几乎完爆WebViewJavascriptBridge,当然,由于WebViewJavascriptBridge诞生的年代比较早,到现在积累的用户非常多(事实上是世界上目前使用最多的),但是时间在流逝,有些东西必将成为历史,DSBridge的出现也注定着WebViewJavascriptBridge将成为历史,如果DSBridge没有实现这个目标,那只有一个可能,那就是DSBridge的作者对其推广不够。

如果你觉的DSBridge不错,想对这个新丁支持一下,想让更多的人能够知道它,请在github上star一下哦,顶起来。

再次贴出DSBridge项目地址:

DSBridge-IOS:https://github.com/wendux/DSBridge-IOS
DSBridge-Android:https://github.com/wendux/DSBridge-Android

预告:下一篇我们将继续将DSBridge 和 老二( github上2.3k star的 https://github.com/lzyzsd/JsBridge)做一个对比,欢迎持续关注。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,392评论 25 707
  • WebSocket-Swift Starscream的使用 WebSocket 是 HTML5 一种新的协议。它实...
    香橙柚子阅读 23,687评论 8 183
  • 前几天我的同学发了一条朋友圈,大意是这样的:他在知乎上看到,很多人动不动就给公务员贴标签,如“不劳而获”、“不肯拼...
    林易子阅读 930评论 1 2
  • 一 自己终于成为上帝了,这是在他杀了第三个人之后的想法。 起初杀人时,他的双手还是不住地颤抖,所以动作一点也不利索...
    谭树君阅读 295评论 0 1
  • 著名教育家苏霍姆林斯基曾说过:“没有科学研究便不可能有教育工作。如果你想让教师的劳动工作给他们带来乐趣,使天天上课...
    悠悠悦耳阅读 334评论 0 5