JSBridge初探

为何关注JSBridge

自从2017年1月9日,微信小程序上线后,小程序生态已经吸引了大批的开发者入驻,开发快捷,快速部署,跨平台是小程序几个优点。到如今各个大平台都会根据自身业务实现各自的小程序平台。小程序隐隐成为新的流量入口。应用生态慢慢再向泛应用生态转变。在这个泛应用生态上会不会有安全问题,我们的检测如何触达;另外小程序框架有没有可能在我们未来的SDK或者2C应用中进行使用?带着这些问题去研究了小程序框架中最重要的核心功能JSBridge。在看技术之前还是回顾一下小程序的历史和现在的状况。

小程序平台发展时间线

  • 2017年1月 微信小程序上线

  • 2018年3月 快应用发布

  • 2018年7月 百度智能小程序上线

  • 2018年9月 支付宝程序、淘宝轻店铺上线

  • 2018年10月 抖音小程序上线

  • 2018年11月 头条小程序上线

  • 2019年5月 QQ小程序上线

  • 2019年7月 360小程序上线

  • 2019年10月 美团小程序上线

小程序数量

小程序统计

据艾媒网统计,2020年小程序数量将达到1400w+

JSBridge是什么

JSBridge很早就出现在软件开发中,它提供一个JS和Native互相调用的功能。在移动开发中,Natvie层指的就是APP的Java层,使用了JSBridge的H5页面可以通过js调用原生系统的一些功能,如打开通讯录,打开相册选取照片等等功能。 微信早期为自己的应用已经提供基于JSBridge的功能,叫WeiXinJSBridge,后来发现这套机制可以抽象统一后对外提供,于是现在微信的JSBridge被封装成JSSDK,也就有了后来的小程序的兴起。

JSBridge框架图

JSBridge的基本框架如上图所示 在Android中使用的是Google的Webkit框架,其中Webview是支持将Native方法注册到一个js函数上,用来处理js层的调用 同样Webview也有一个evaluateJavascript方法可以调用已经加载的js方法 JSBridge其实就是利用上述两个方法进行封装而成的JS和JAVA层相互通信的通道。

JSBridge的小例子

俗话说的好Talk is cheap. Show me the code。为了更深刻的理解js和native的交互过程,写了一个最简单的例子。

  1. 首先创建一个app工程,就用empty view就可以

  2. 修改layout的activity_main.xml, 创建Webview

     <?xml version="1.0" encoding="utf-8"?>
     <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:app="http://schemas.android.com/apk/res-auto"
         xmlns:tools="http://schemas.android.com/tools"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         tools:context=".MainActivity">
    
         <WebView
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:id="@+id/webView"
             />
    
     </androidx.constraintlayout.widget.ConstraintLayout>
  3. 在src/main路径下创建assets目录,并在assets目录下创建index.html文件,写入如下内容

     <!DOCTYPE html>
     <html>
     <head>
         <title>WebView与JS方法交互</title>
    
         <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
         <meta http-equiv="description" content="this is my page">
         <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    
         <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
    
     </head>
    
     <body>
     <input type="button" value="Say hello"
         onClick="showAndroidToast('Hello Android!')" />
    
     <script type="text/javascript">
             //调起本地的Java方法
             function showAndroidToast(toast) {
                 window.Android.showToast(toast);
             }
         </script>
     </body>
     </html>
  4. 修改MainActivity

     package com.wq.jsbridge;
    
     import androidx.appcompat.app.AppCompatActivity;
    
     import android.os.Bundle;
     import android.webkit.JavascriptInterface;
     import android.webkit.WebSettings;
     import android.webkit.WebView;
     import android.webkit.WebViewClient;
     import android.widget.Toast;
    
     public class MainActivity extends AppCompatActivity {
         private WebView mWebView;
    
         @Override
         protected void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
             setContentView(R.layout.activity_main);
    
             initWebView();
         }
    
         private void initWebView() {
             WebView mWebView = (WebView) findViewById(R.id.webView);
    
             //启用支持javascript
             WebSettings settings = mWebView.getSettings();
             settings.setJavaScriptEnabled(true);
    
             mWebView.addJavascriptInterface(new JsBridgeJavaScriptInterface(), "Android");
    
             //WebView加载web资源
             mWebView.loadUrl("file:///android_asset/index.html");
             //覆盖WebView默认使用第三方或系统默认浏览器打开网页的行为,使网页用WebView打开
             mWebView.setWebViewClient(new WebViewClient() {
                 @Override
                 public boolean shouldOverrideUrlLoading(WebView view, String url) {
                     // TODO Auto-generated method stub
                     //返回值是true的时候控制去WebView打开,为false调用系统浏览器或第三方浏览器
                     view.loadUrl(url);
                     return true;
                 }
             });
         }
    
         final class JsBridgeJavaScriptInterface {
             /** JS调用native方法显示一个Toast */
             @JavascriptInterface
             public void showToast(String toast) {
                 Toast.makeText(getApplicationContext(), toast, Toast.LENGTH_SHORT).show();
             }
         }
     }
  5. 之后编译运行时就可以看到Activity中出现了一个button,点击button就会调用到Native的Toast方法进行

    运行截图

下一步如何丰富这个例子

上面的例子展示了如何从js方法中调用native方法,并没有展示Java回调js的过程,并且也没有对接口进行统一封装 回调的实现可以有两种方式:

  1. 返回值通过Native方法的返回值给出,一般是string类型,这个返回值可以直接返回到js方法中,在js中添加对返回值的处理函数

  2. 在js层实现一个供native调用的统一入口,在native执行完成后,准备返回值和callback函数名,通过evaluateJavascript方法处理

封装的话主要是对js调用native的接口以及native调用js的接口进行统一约定,其中包含API 名,参数格式,返回值格式等等

参考项目

ZJsBridge 这个项目很好的展示了双向调用的过程,并且整个代码结构也很清晰,可以作为后续使用和优化的参考

Last updated

Was this helpful?