EasyBridge:一种简单的js-bridge方案设计

日前在总结项目中已有的jsbridge方案的时候,由于以为存在诸多不合理的地方,因此针对业务的场景以及实际的状况,重写了一个简单易用的js-bridge方案,命名为EasyBridgejava

EasyBridge是一个简单易用的js-bridge的工具库,提供了平常开发中,JavaScript与Java之间通信的能力,与其余常见的js-bridge工具库实现方案不一样,EasyBridge具有如下几个特色:react

  • 基于Android WebViewaddJavascriptInterface特性实现
  • 提供了基于接口粒度的安全管理接口
  • 轻量级,而且简单易用。以这个工具库做为依赖,只须要编写实际通信接口

实现原理说明

混合开发一直是工业界移动端开发比较看好的技术手段,结合h5的特性,可以更好的支持业务发展的须要,不只快速上线、部署功能并且可以快速响应线上的bug。目前混合开发的方案包括:android

EasyBridge就是一种简单的JSBridge解决方案。在众多的解决方案中,都是在利用系统的WebView所开放的权限和接口,打开Java与JavaScript通信的渠道,这些方案的实现原理分别包括:git

  • 拦截onJsPrompt()方法github

    WebView中的页面调用了JavaScript当中的window.prompt()方法的时候,这个方法会被回调。并且这个方法不只能获取到JavaScript传递过来的string字符串内容,同时也能返回一段string字符串内容被JavaScript接收到,是一个至关适合构建bridge的入口方法。web

  • 拦截shouldOverrideUrlLoading()方法chrome

    当页面从新load URL或者页面的iframe元素从新加载新的URL的时候,这个方法被回调。apache

  • addJavascriptInterface()接口react-native

    这个接口简单却强大,经过这个接口,咱们可以直接把Java中定义的对象在JavaScript中映射出一个对应的对象,使其直接调用Java当中的方法,可是,在android 4.1及以前的版本存在着严重的漏洞,因此一直被忽视。安全

EasyBridge在众多的解决方案中,最终了选择了addJavascriptInterface()接口做为方案的基础,主要基于如下几点考量:

  • 目前Android版本已经到了9.0版本,市面上Android4.4以前的版本手机占有率已经很低,不少业务都已经把最低兼容版本定在了4.2以上,所以不须要考量4.1如下存在的漏洞问题;
  • addJavascriptInterface()可以提供最简单的同步调用
  • addJavascriptInterface()evaluateJavascript()/loadUrl结合,可以带来更加简单的异步调用的解决方案

方案设计说明

EasyBridge最终方案实现,只支持了异步调用的方式,主要是基于如下的考量:

  • 同步的调用能够转化为异步调用的方式,保留一种调用方式会使得整个方案更加简单;

方案结构

EasyBridge的方案结构以下图所示:

EasyBridge总共会向页面中注入两个JavaScript对象,:

  • easyBridge

    在页面加载完成onPageFinished()回调的时候,经过执行工具库中的一个js文件注入的。这个对象主要的做用是定义了业务页面的JavaScript代码调用native的Java代码的规范入口,对象中定义的一个最关键的函数就是callHandler(handlerName, args, callback),这就是桥梁的入口。实际上在这个方法的内部,最终就是经过下面的**_easybridge**对象进入到Java代码层。

  • _easybridge

    经过addJavascriptInterface()映射和注入的一个对象,这个对象提供了实质的入口方法enqueue(),在这个方法当中代码的路线从JavaScript层进入到了Java层,开启了二者的交互。

接口分发

实际上,咱们能够经过@JavascriptInterface注解开放不少的接口给JavaScript层调用,也能够经过addJavascriptInterface()映射多个Java对象到JavaScript层,可是为了维护简单和通信方便,EasyBridge的设计只提供了一个入口和一个出口。全部须要开放给JavaScript层的功能,都是经过构建接口实例进行处理。

接口的定义以下:

public interface BridgeHandler {

    String getHandlerName();

    void onCall(String parameters, ResultCallBack callBack);

    SecurityPolicyChecker securityPolicyChecker();
}
复制代码

实际的工做流程以下图所示:

最开始初始化的时候须要注册全部能够被JavaScript层调用的业务接口。在运行的过程当中,enqueue()入口当中会根据协议定义,经过接口名称找到对应的处理接口实例,并触发接口响应。而且最终的接口响应都在入口处进行回传。所以,实际上,_easybridge对象(在Java层中,实际上是EasyBridge的实例)就是一个枢纽站,作任务的分派和结果的传递。

安全控制

每个BridgeHandler实例,均可以定义本身的安全控制策略,对应的是一个SecurityPolicyChecker的实例,其定义以下:

public interface SecurityPolicyChecker {
    boolean check(String url, String parameters);
}
复制代码

每个接口在接收到分派的指令以前,会先调用其安全控制策略,根据当前加载的页面地址以及传入的指令参数判断是否须要进行指令的分派,不然将会直接命令安全受限,错误返回,结果调用。

方案使用

EasyBridge是一个极其简单易用的方案,只须要简单的几步便可具有JavaScript层与Java层通信的能力。在引入EasyBridge库做为依赖以后:

  1. 继承/直接使用EasyBridgeWebView

    EasyBridgeWebView是功能的承载者,负责了bridge对象的注入,以及handler接口的管理(内部使用`EasyBridge对象管理)

  2. 根据业务以及协议定义实现对应的BridgeHandler实例

  3. 在加载第一步的webview的实例页面绑定第二步构造的handler实例

以上三步即完成了全部的工做。

若是你须要调试这个方案的实际工做,你能够在把手机链接到电脑以后,使用chrome进行调试。EasyBridge会把传递的结果信息以及错误信息打印在控制台之上。你将会很容易的感知和发现问题。关于在Chrome中调试web页面,你能够参考官方的教程文档Remote Debugging WebViews

关于这个方案目前已经具有的feature,以及demo,欢迎访问个人GitHub仓库EasyBridge。同时欢迎你们对这个方案的设计和实现提出大家的改进意见,谢谢

相关文章
相关标签/搜索