JSBridge

JSBridge

原生APP开发中有一个叫WebView的组件,这个组件可以加载HTML文件。JSBridge则是WebView内的JS环境与Native沟通的一个渠道,它允许WebView去调用原生的API(比如拍照,截屏,录屏等),极大的扩展了WebView的功能

img

WebView

WebView是移动端提供的运行JS的环境,是系统渲染Web网页的一个控件,可与JS交互,实现了混合开发。WebView除了能加载指定URL外,还可以对URL请求,JS对话框,进度加载,页面交互进行处理

JSBridge实现原理

Web端和Native可以类比于Client/Server模式,Web端调用原生接口时,就如同Client向Server端发送一个请求,JSBridge在此充当类似于HTTP协议的角色,实现JSBridge主要是两点:

  • 将Native端原生接口封装为JS接口
  • 将Web端JS接口封装成原生接口

NativeWebNative\rightarrow Web

Native端到Web端比较简单,JS作为解释型语言,可以随时随地通过解释器执行一段代码,所以可以将拼接的JS代码字符串传入JS解释器即可

Android 4.4以前,只能通过loadUrl来实现,并且无法执行回调:

String jsCode = String.format("window.showWebDialog('%s')", text);
webView.loadUrl("javascript: " + jscode);

Android 4.4之后,提供了evaluateJavascript来执行JS,并且可以获取返回值执行回调:

String jsCode = String.format("window.showWebDialog('%s')", text);
webView.evaluateJavascript(jsCode, new ValueCallback<String>() {
	@Override
	public void onReceiveValue(String value) {
	
	}
});

WebNativeWeb\rightarrow Native

URL Scheme

URL Scheme是类URL的一种请求格式,格式如下:

<protocol>://<host>/<path>?<query>#fragment

我们可以自定义JSBridge通信的URL Scheme,比如:jsbridge://showToast?text=hello,Native加载WebView之后,Web发送的所有请求都会经过WebView组件,所以Native可以重写WebView里的方法,从而拦截Web发起的请求,对请求的格式进行判断:

  • 如果符合我们自定义的URL Scheme,对URL进行解析,拿到相关操作,进而调用原生Native的方法
  • 如果不符合自定义的URL Scheme,直接转发,请求真正的服务

这种方式从早期就存在,兼容性很好,但是是基于URL的方式,长度受到限制并且不太直观,数据格式有限制,而且建立请求时间耗时

向WebView注入JS API

这个方法会通过WebView提供的接口,APP将Native相关的接口注入到JS的Context(window)中,一般来说,这个对象内的方法名与Native相关方法名是相同的,Web端就可以直接在全局window下使用这个暴露的JS对象,进而调用Native端的方法,这个过程会更直观简单,不过存在兼容性问题

webView.addJavascriptInterface(new NativeBridge(this), "NativeBridge");

class NativeBridge {
	private Context ctx;
	NativeBridge(Context ctx) {
		this.ctx = ctx;
	}
	
	@JavascriptInterface
	public void showNativeDialog(String text) {
		new AlertDialog.Builder(ctx).setMessage(text).create().show();
	}
}

在Web端直接调用这个方法即可:

window.NativeBridge.showNativeDialog("hello");

with Callback

目前站在一端的角度而言,还是一个单向通信的过程

但其实稍微修补一下之前的思路,就能实现调用并获取返回值的操作了:在一段调用时,在参数中加一个callbackId标记对应的回调,对端收到调用请求后,进行实际操作,如果带有callbackId,对端再进行一次调用,将结果、callbackId回传回来

img