Android中的JSBridge是H5与Native通信的桥梁,其作用是实现H5与Native间的双向通信。要实现H5与Native的双向通信,解决如下四个问题即可:
1、Java如何调用JavaScript
2、JavaScript如何调用Java
3、方法参数以及回调如何处理
4、通信的数据格式是怎么样的
下面从以上问题依次开始讨论:
1、Java如何调用JavaScript
在Android 中,Java与JavaScript的一切交互都是依托于WebView的。可通过如下方法来完成,其中function()即为JavaScript代码,来实现相应的具体H5层功能
1 | WebView.loadUrl("javascript:function()"); |
2、JavaScript如何调用Java
要实现在JavaScript中调用Java,就需要在JavaScript中有触发Java方法的对象和方法。在JavaScript中,当调用window对象的prompt方法时,会触发Java中的WebChromeClient对象的onJsPrompt方法,因此可以利用这个机制来实现js调用native的代码。
3、方法参数以及回调处理
任何IPC通信都涉及到参数序列化的问题,同理,Java与JavaScript之间只能传递基础类型(包括基本类型和字符串),不包括其他对象或者函数。所以可以采用json格式来传递数据。JavaScript与Java相互调用不能直接获取返回值,只能通过回调的方式来获取返回结果。
4、通信的数据格式
Java与JavaScript通信需要遵循一定的通信协议,可以仿照HTTPS协议来将此协议定义为jsbridge协议:
1 | jsbridge://className:port/methodName?jsonObj |
当js调用native功能时,应当指定native层要完成某个功能调用的类名(className)和方法名(methodName),以及js传递过来的参数(jsonObj)。port值是指当native需要将操作结果返回给js时,在js中定义一个callback,并将这个callback存储在指定的位置上,这个port就定义了callback的存储位置。
JSBridge的具体工作流程图如上所示:
1、js触发调用native层的行为
1 | JSBridge.call(className, methodName, params, callback); |
将call方法中的参数组合成jsbridge协议格式的url。然后通过prompt方法将url传递到native层。
1 | window.prompt(url); |
2、通过WebChromeClient来获取js传递过来的url.
1 | public class JSBridgeWebChromeClient extends WebChromeClient { |
3、JSBridge类管理暴露给前端方法,前端调用的方法应该在此类中注册才可使用。register的实现是从Map中查找key是否存在,不存在则反射取得对应class中的所有方法,具体方法是在BridgeImpl中定义的,方法包括三个参数分别为WebView、JSONObject、CallBack。如果满足条件,则将所有满足条件的方法put到map中。
1 | private static Map<String, HashMap<String, Method>> exposedMethods = new HashMap<>(); |
JSBridge类中的callJava方法就是将js传递过来的URL解析,根据将要调用的类名从刚刚建立的Map中找出,根据方法名调用具体的方法,并将解析出的三个参数传递进去。
1 | public static String callJava(WebView webView, String uriString) { |
4、CallBack类是用来回调js中回调方法的Java对应类。Java层处理好的返回结果是通过CallBack类来实现的。在这个回调类中传递的参数是JSONObject(返回结果)、WebView和port,port应与js传递过来的port相对应。
1 | private static Handler mHandler = new Handler(Looper.getMainLooper()); |
5、JSBridgeImpl类中定义所有暴露给前端的方法的具体实现。本文以showToast为例来通过native代码显示toast,并给出js的回调函数,返回一个JSONObject对象。
1 | public static void showToast(WebView webView, JSONObject param, final Callback callback) { |
6、在js中通过
1 | JSBridge.call('bridge','showToast',{'msg': 'Hello'}, function(res){alert(JSON.stringi |
即可调用在Java层定义的showToast方法,调用前不要忘记在java层的JSBridge中注册该方法。
1 | JSBridge.register("bridge", BridgeImpl.class); |
二、总结:
JSBridge的基本原理为:
H5->通过某种方式触发一个url->Native捕获到url,进行分析->原生做处理->Native调用H5的JSBridge对象传递回调。如下图
三、安全性:
- Android4.2以下,addJavascriptInterface方法有安全漏洞,js代码可以获取到Java层的运行时对象,来伪造当前用户执行恶意代码。
- ios7以下,JavaScript无法调用native代码。
- 通过js声明的对象,是通过loadUrl注入到页面中的,所以这个对象是js对象,而不是Java对象,没有getClass等Object方法,因此也无法获得Runtime对象,避免了恶意代码的注入。
- JSBridge采用URL解析的交互方式,是一套成熟的解决方案,便于拓展,无重大安全性问题。