Android中webview与native之间的交互方式(jsbridge)

来源:互联网 发布:手机视频慢放软件 编辑:程序博客网 时间:2024/06/01 09:03

Android中webview与native之间的交互方式(jsbridge)

前言

​ 随着H5的广泛使用,Android开发过程中免不了会使用网页来做展示,那么,web与native之间的通信就显得尤其重要了,其实际上是JavaScript与java之间的通信;如图所示,我们开发过程中需要在native中调用JavaScript,或者是在JavaScript中调用native。

这里写图片描述
* JavaScript调用java

JavaScript调用java的方式可以分为两类,一是通过捕获url scheme的方式,二是利用原生接口实现调用。

1. 捕获url scheme的方式

​ 核心思想是:web端与native首先协商好通信中使用的url的格式,紧接着web端通过一定的方式将url发送出去,最后native层捕获url,并进行分析后再去调用原生方法。这种方法也是目前被广泛使用的方式。

a) 首先第一步是约定好url的格式,例如这里约定为:


JSBridge://bridge:129129723/showToast?{"msg":"Hello JSBridge"}

其中showToast为需要调用的native层方法,{“msg”:”Hello JSBridge”}为向native传递的json数据。

b) 约定好传递格式后,web端需要触发native层去捕获url。

​ Android中为我们提供了两个类WebViewClient和WebChromeClient,这两个类分别为我们提供了一些方法可以使用。当有任何url在webview中使用时都会被WebViewClient的shouldOverrideUrlLoading函数拦截,因此我们可以利用这个特性,在JavaScript中构建一个1像素的iframe来触发这个函数。web端代码如下:


var url = 'JSBridge://bridge:129129723/showToast?{"msg":"Hello JSBridge"}';
var iframe = document.createElement('iframe');
iframe.style.width = '1px';
iframe.style.height = '1px';
iframe.style.display = 'none';
iframe.src = url;
document.body.appendChild(iframe);

Android端代码:


webView = (WebView) findViewById(R.id.webView);
webView.setVerticalScrollbarOverlay(true);
//设置WebView支持JavaScript
webView.getSettings().setJavaScriptEnabled(true);
String url = "file:///android_asset/test.html"; //加载本地html
webView.loadUrl(url);
webView.setWebViewClient(new JsbridgeWebViewClient());

其中JsbridgeWebViewClient继承WebViewClient,并重写shouldOverrideUrlLoading方法,并在里面实现调用原生方法的逻辑。

​ 其次,WebChromeClient提供了三个原生的方法,当在JavaScript中使用window.alertwindow.confirmwindow.prompt三个方法时会相应的触发WebChromeClient对象的onJsPrompt、onJsAlert、onJsConfirm方法,所以我们也可以在前端通过这三种方式触发native捕获url。web端代码如下:


var url = 'JSBridge://bridge:129129723/showToast?{"msg":"Hello JSBridge"}';
window.prompt(uri, "");

Android端代码只要将上面的JsbridgeWebViewClient继承WebChromeClient ,并重写onJsPrompt、onJsAlert、onJsConfirm方法即可,这里就不再重复。

c) native层捕获到url后,如何调用?

​ 通过解析url,可以得到需要调用的native方法名以及json数据;这里举例是调用native层的showToast方法,我采用反射的方式来进行调用,核心代码:

“`
public static void showToast(WebView webView, JSONObject param) {
String message = param.optString(“msg”);
Toast.makeText(webView.getContext(), message, Toast.LENGTH_SHORT).show();
}

public static String callJava(WebView webView, String uriString, Object owner) {
String methodName = “”;
String className = “”;
String param = “{}”;
String port = “”;
if (!TextUtils.isEmpty(uriString) && uriString.startsWith(“jsbridge”)) {
Uri uri = Uri.parse(uriString);//解析url
className = uri.getHost();
param = uri.getQuery();
port = uri.getPort() + “”;
String path = uri.getPath();
if (!TextUtils.isEmpty(path)) {
methodName = path.replace(“/”, “”);
}
}
Class classType = owner.getClass();
Method showToastMethod = null;
try {
showToastMethod = classType.getMethod(methodName,new Class[]{WebView.class,JSONObject.class});
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
showToastMethod.invoke(owner, webView, new JSONObject(param));//反射调用showToast方法
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
“`

​ 以上是通过捕获url scheme实现JavaScript调用java的方式。

**2. 使用原生方法 **addJavascriptInterface

​ Android为我们提供了addJavascriptInterface方法,JavaScript可以直接调用java方法,但该方法在Android 4.2以下是存在安全隐患的,可参考,官方在Android4.2进行了修复,在使用addJavascriptInterface方法时,必须在提供给JavaScript调用的方法前添加@JavascriptInterface。例如在Android端将showInfoFromJs和getInfoFromJs提供给js调用:

private class JsInterface {    private Context mContext;    public JsInterface(Context context) {        this.mContext = context;    }    //在js中调用window.test.showInfoFromJs(name),便会触发此方法。    @JavascriptInterface    public void showInfoFromJs(String name) {        Toast.makeText(mContext, name, Toast.LENGTH_SHORT).show();    }    @JavascriptInterface    public  void getInfoFromJs(int a, int b){        int c = a+b;        Toast.makeText(mContext, ""+c, Toast.LENGTH_SHORT).show();    }}
//设置WebView支持JavaScriptwebView.getSettings().setJavaScriptEnabled(true);String url = "file:///android_asset/test.html";webView.loadUrl(url);//在js中调用本地java方法webView.addJavascriptInterface(new JsInterface(this), "test");

在js中通过以下进行调用:

var name = document.getElementById("name_input").value;var a = 1;var b = 2;window.test.showInfoFromJs(name);window.test.getInfoFromJs(a,b);
  • java调用JavaScript

    ​ java调用javascript的方法比较简单,因为android为我们提供了相应的方法, 4.4之前通过loadUrl的方式,而在4.4之后提供了evaluateJavascrip异步调用的方式。这里就只举例loadurl的方法。

    String msg = ((EditText) findViewById(R.id.input_et)).getText().toString();//调用js中的函数:showInfoFromJava(msg)webView.loadUrl("javascript:showInfoFromJava('" + msg + "')");

    以上就是js与java互相调用的方式。