天天看点

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

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

前言

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

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

* 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.alert,window.confirm,window.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支持JavaScript
webView.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 = ;
var b = ;
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互相调用的方式。