从Native和H5两端看JsBridge

之前一直在使用JsBridge,也知道大概的原理,但是没有去深究。最近有空研究了一下。以Android和H5两端的视角分析一下其中的原理

需求背景

Native 加载 H5 页面,H5页面可以调用Native的方法,Native也可以调用H5页面的方法,并且可以传递数据和设置回调。
这基本上是一个Hybrid应用所具有的基本功能,下面就来分析下具体的实现过程。

官方方案

  1. Android 4.2 之前有漏洞,js可以访问任何public方法,最主要的是getClass方法,至于具体情况,有兴趣的可以网络search一下。
  2. Android 4.2 之后添加了限制,只有@JavascriptInterface注解的方法,才能在js中访问。

简要说明

如果只考虑Android4.2 之后的版本,可以使用官方方案,虽说增加了安全性,但是也不保证绝对安全。另一方面还需要解决Android 4.2之前的版本,所以就衍生出了第三种解决方案。

业界通常的做法就是拦截js的prompt/alert/confirm方法,然后会执行到WebChromeClient中相应的方法onJsPrompt/onJsAlert/onJsConfirm,从而做到js调用Native的方法。因为alert和confirm方法在js中是常用的,prompt方法不常用,所以一般选择拦截prompt方法。

如果只是说原理,那现在就可以结束了。可是我是一个较真的人,所以有了下文。如果你也不满足于上面提到的这些,就看下面的具体分析吧!

自定义方案

加载

上面说了可以通过拦截js的prompt函数来执行Native的onJsPrompt方法,从而执行你想执行的Native方法。但这仅仅是原理,在一个App中怎么判断我要执行哪一个方法呢?调用的方法有没有限制?下面就来介绍下我司的实际解决方案

  1. 在App中定义所有可以被Js访问的方法,由于方法来自各个模块,方法名可能重复,所以定义了module的概念,即定义所有的module,存在Bridge类的map<moduleName,ExportModule>,这里定为JavascriptBridge(下同),并提供给外部获取modules {"module": moduleName,"methods": ["methodA",....]}
    说明:
    1. 识别method的方式跟Google官方的方案一样,采用注解的方式。即在method上面添加注解,这里定为JsBridge(下同)
    2. ExportModule 类有 String moduleName; Class moduleClass; 两个变量
    和一个 private map 提供根据注解名找到所有提供给js的Method,存放在map<"methodA",MethodA>中,methodA为注解值,MethodA为Method.Class
  2. 自定义webView 添加UserAgent 标识,这里定为 "droid"(下同) ,这里的目的是让js识别是需要处理的url
  3. Native load(url)
    小总结:以上三部是在Native需要做的事情,主要就是准备给js调用的方法,加载url
  4. H5页面收到请求url,引入bridge.js(下同) 会去初始化,会根据userAgent判断是否需要去处理,需要处理的话,通过调用window.prompt来调用Native的onJsPrompt方法获取Native的JavascriptBridge中存储的modules,然后注册到bridge.js
    小总结:这一步就是js初始化的时候获取Native的modules,注册到js中

总结:整个流程就是Native和Js两端各准备一个bridge,Native的bridge提供modules,js的bridge注册Native提供的modules。这就是bridge存在的意义--提供一个桥梁,让两边通信

加载过程.png

调用

H5调用Native

  1. js 提供一个方法bridgecall (下同),用来拼装一个url 包括 type: 调用方法/回调方法 module method args。
  2. bridgecall 会 document.createElement 一个iFrame,设置它的src为上面拼装的url,这样就会发起一个url的请求,随后移除掉这个iFrame
  3. H5调用js注册的module的方法,会统一调用到invokeNative方法调用bridgecall方法,从而发起一个url请求
  4. webViewClient的shouldOverrideLoading()方法会拦截到url,然后解析url,找到相应的Method执行。

Native调用 H5

  1. loadurl("javascript:js的方法invokeJSMethod(module,method,args)"),这里的args,如果有回调函数,bridge会存一个map<callbackidFormat,callBackFun> ,然后把callbackIdFormat作为参数加载args中。
  2. js 执行invokeJSMethod方法,解析callbackIdFormat,如果匹配到的话说明有回调函数,在执行完方法后会把callbackIdFormat作为参数,执行callbackNavite方法
  3. callbackNative 到invokeNative方法调用bridgecall发起url请求
  4. webViewClient的shouldOverrideLoading()方法会拦截到url,解析到时回调请求,就去获取callbackidFormat对应的callBackFun。

总结:
H5调用Native就是拼装url,发起请求,Native拦截去请求Native的方法,如需要回调,之前url带上回调函数,去执行js的函数,跟Native调用H5一样。
Native调用H5就是执行H5中的方法,若需要回调,跟H5调用Native一样

加载和互相调用.png

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容