0、在开发 Hybrid App 的时候,经常需要处理 JavaScript 和 Native 交互的问题,其实从根本上说,是一个通信方式的问题,至于具体实现,其实有很多的方案。
1、JavascriptBridge
Android 中的 WebView 有 addJavascriptInterface 接口,该接口的功能是将一个 Java 对象注入到 WebView 的 window 对象中,即在 H5 页面运行的时候,在 window 对象中会增加一个元素,该元素包含 Java 对象中的方法。
例如:
private class JavascriptBridge {
@JavascriptInterface
public String run(String param) {
// todo by param and return a result
}
}
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(new JavascriptBridge(), "AppBridge");
这时候在 H5 页面就可以通过
var result = window.AppBridge.run('Hello World');
类似的方法进行调用 ,并可以获得由原生代码返回的结果。
该方法的安全性问题:
在 Android 4.2 即 API 17 以下,没有 @JavascriptInterface 注解,默认的情况下允许调用注入的 Java 对象的所有方法,因此存在利用反射的方式执行任意的 Java 方法的可能性,甚至可以执行某个进程。如果有心人在 H5 页面植入精心设计好的代码,那么在打开这个 H5 页面的时候,存在手机变成肉鸡的可能。
解决方案:
一个是从 Android 4.2 开始适配,另一个是不使用 addJavascriptInterface 而通过重写 onJsPrompt 方法。
其他注意点:
一个是代码混淆的时候需要对注入的对象做处理,不能混淆用到的方法名称。另一个是由 H5 页面发起的方法不是在主线程上运行的,需要随时注意跨线程的问题。还有一点是,系统默认在 window 对象中增加了 searchBoxJavaBridge_ 等对象,因此在启用 JavaScript 之后要加入以下代码:
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) {
mWebView.removeJavascriptInterface("searchBoxJavaBridge_");
mWebView.removeJavascriptInterface("accessibility");
mWebView.removeJavascriptInterface("accessibilityTraversal");
}
该段代码的作用是移除系统自动往里面添加的 Java 对象,防止被攻击者利用。
2、重写 onJsPrompt 方法
WebChromeClient 提供了一个方法:
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
return false;
}
该方法允许我们重写 JS 输入框的样式,即可以自定义在 H5 页面调用 prompt 方法时,浏览器所做出的响应。因此,通过重写该方法,我们可以通过 message 和 defaultValue 获得 JS 传递过来的参数,并通过 JsPromptResult 给 H5 页面返回相应的值。该方法虽然有一些投机取巧,通信协议可能也需要专门设计,但确实可以解决 JavascriptInterface 带来的安全性问题。
3、拦截 URL 跳转
网络上大多数的解决方案都是基于拦截 URL 跳转实现,即通过重写 shouldOverrideUrlLoading 方法提供的参数获得 H5 页面传递过来的参数,然后通过 loadUrl 方法执行一段 JavaScript 代码给 H5 页面返回值。这是一个比较方便也比较通用的方法,因为在 iOS 开发当中,使用这个方法进行交互也是很方便的,因此得到广泛的使用。网络上有很多开源的框架也是基于这个原理实现的,例如:https://github.com/lzyzsd/JsBridge 等。
4、其他
其实从根本上说,只要解决通信问题即可,其他像内建一个 Web 服务器通过 WebSocket 通信理论上也可以解决问题。只不过解决起来可能比较复杂。