为何关注JSBridge
自从2017年1月9日,微信小程序上线后,小程序生态已经吸引了大批的开发者入驻,开发快捷,快速部署,跨平台是小程序几个优点。到如今各个大平台都会根据自身业务实现各自的小程序平台。小程序隐隐成为新的流量入口。应用生态慢慢再向泛应用生态转变。在这个泛应用生态上会不会有安全问题,我们的检测如何触达;另外小程序框架有没有可能在我们未来的SDK或者2C应用中进行使用?带着这些问题去研究了小程序框架中最重要的核心功能JSBridge。在看技术之前还是回顾一下小程序的历史和现在的状况。
小程序平台发展时间线
小程序数量
据艾媒网统计,2020年小程序数量将达到1400w+
JSBridge是什么
JSBridge很早就出现在软件开发中,它提供一个JS和Native互相调用的功能。在移动开发中,Natvie层指的就是APP的Java层,使用了JSBridge的H5页面可以通过js调用原生系统的一些功能,如打开通讯录,打开相册选取照片等等功能。 微信早期为自己的应用已经提供基于JSBridge的功能,叫WeiXinJSBridge,后来发现这套机制可以抽象统一后对外提供,于是现在微信的JSBridge被封装成JSSDK,也就有了后来的小程序的兴起。
JSBridge的基本框架如上图所示 在Android中使用的是Google的Webkit框架,其中Webview是支持将Native方法注册到一个js函数上,用来处理js层的调用 同样Webview也有一个evaluateJavascript方法可以调用已经加载的js方法 JSBridge其实就是利用上述两个方法进行封装而成的JS和JAVA层相互通信的通道。
JSBridge的小例子
俗话说的好Talk is cheap. Show me the code
。为了更深刻的理解js和native的交互过程,写了一个最简单的例子。
首先创建一个app工程,就用empty view
就可以
修改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>
在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>
修改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();
}
}
}
之后编译运行时就可以看到Activity中出现了一个button,点击button就会调用到Native的Toast方法进行
下一步如何丰富这个例子
上面的例子展示了如何从js方法中调用native方法,并没有展示Java回调js的过程,并且也没有对接口进行统一封装 回调的实现可以有两种方式:
返回值通过Native方法的返回值给出,一般是string类型,这个返回值可以直接返回到js方法中,在js中添加对返回值的处理函数
在js层实现一个供native调用的统一入口,在native执行完成后,准备返回值和callback函数名,通过evaluateJavascript方法处理
封装的话主要是对js调用native的接口以及native调用js的接口进行统一约定,其中包含API 名,参数格式,返回值格式等等
参考项目
ZJsBridge 这个项目很好的展示了双向调用的过程,并且整个代码结构也很清晰,可以作为后续使用和优化的参考