JSBridge小科普

时间:2022-07-25
本文章向大家介绍JSBridge小科普,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

做Hybird APP开发的同学,应该对JSBridge不陌生,它用于H5页面和Native(Android或者iOS)通信。常用的三方库如Dsbridge系列(https://github.com/wendux/DSBridge-Android)。那么,你知道JSBridge到底是如何在两端进行通信的吗?

下面的实例代码,Native端以Android为例。

1. Web调用Native能力

1.1 通过URI Schema请求(全局注册)

Native应用可以在移动端系统中注册一个Schema协议的URI,这个URI可以在系统的任意地方授权访问,用来调起一段原生方法,或者唤起一个原生界面。

于是,Native WebView控件中的H5页面,可以通过JS代码请求这个通用Schema协议。 比如,通过添加一个不可见的iframe,设置其src属性,发送一个URI请求。

let iframe = document.createElement('iframe');
iframe.setAttribute('style', 'display:none');
document.body.appendChild(iframe);
iframe.setAttribute('src', 'myapp://className/method?args')

整个调用流程如下图。一旦系统捕获到注册表中的Schema URI,就会通过此URI地址执行该Schema协议定义的Native操作,执行一段Native代码或者打开APP的某个页面(如打开摄像头,唤起图片预览功能,跳转APP支付页面等)

jsBridge_native Schema.png

1.2 通过代码注入(针对webView组件)

以Android为例,可以通过addJavascriptInterface方法将Native的一个对象注入到页面中,供JS调用。

/** 
* 添加javascriptInterface 
* 第一个参数:这里需要一个与js映射的java对象 
* 第二个参数:该java对象被映射为js对象后在js里面的对象名,在js中要调用该对象的方法就是通过这个来调用 
*/  
 webView.addJavascriptInterface(new JSInterface(), "android");  

 private final class JSInterface{  
    /** 
     * 注意这里的@JavascriptInterface注解, target是4.2以上都需要添加这个注解,否则无法调用 
     * @param text 
     */  
    @JavascriptInterface  
    public void showToast(String text){  
         Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();  
    }  
}  
--------------------------------------------------------------------
/**
 * js中调用java方法
 */
android.showToast('toast');

Native会向webView全局作用域注入一个android的全局对象,该对象上有showToast的方法。

Android 4.2 之前注入对象的接口是 addJavascriptInterface ,但是由于安全原因慢慢不被使用(4.2以下版本,通过JS可以访问设备SD卡上面的任何内容,甚至是联系人信息,短信等。此为安全漏洞)。

现在,一般会通过拦截JS原生的window.confirmwindow.prompt方法,从而达到H5向Native通信的目的。 如,在 Webview 上添加 onJsConfirmonJsPrompt 监听(其实,监听window.console或者window.alert也是可以的,但是这两个方法在JS coding中比较常用,所以为了避免不必要的事件触发,一般我们不会选择在客户端劫持它们)。代码如下:

webview.setWebChromeClient(new WebChromeClient());

public class JSBridgeWebChromeClient extends WebChromeClient {
    @Override
    public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
        String handledRet = parentEngine.bridge.promptOnJsPrompt(origin, message, defaultValue);
        ......
        return true;
    }
}

2. Native调用Web函数

反之,如果Native需要主动调用JS的方法,又该怎么做呢?

很简单,只要 H5 将 JS 方法暴露在 Window 上给 Native 调用即可。 是不是非常像客户端注册 Schema URI呢?

JS注册好函数,Native就可以调用了。

Android 4.4 以前,通过 loadUrl 方法,执行一段 JS 代码来实现(缺点是效率低,无法获得返回结果,且调用的时候会刷新 WebView):

/**
 * js中声明全局函数
 */
<script>
function log(msg) {
    console.log(msg);
}
</script>

--------------------------------------------------------------------
/**
 * 设置与Js交互的权限
 */
webSettings.setJavaScriptEnabled(true);

private final class JSInterface{  

    @JavascriptInterface  
    public void showJsLog(String text){  
        webView.loadUrl("javascript:log('"+text+"')");  
    } 
}  

4.4 以后,可以使用 evaluateJavascript 方法实现(效率更高,可获取返回值,调用时候不刷新WebView)

String text = "hello world";
webView.evaluateJavascript("javascript:log('"+text+"')", new ValueCallback<String>() {
  @Override
  public void onReceiveValue(String value){
   ......
  }
});

小结

Native和H5需要在接口设计上达成一致。只要API规定好,后续通信实现就不难了。