js 与原生交互分为两种情况:js 调用原生方法,原生调用 js 方法。
本文将对这两种情况分别讲解,H5 端用 vue 实现。
一、前期准备(Vue项目准备)
本文的 H5 端用Vue 实现,所以在正式开始前先把 Vue 项目环境准备好。
项目写好后,执行 npm run serve 命令启动项目,启动成功后会在命令行看到两个地址:

http://localhost:8080/ 和 http://10.0.0.188:8080/
10.0.0.188 是我本机的 ip 地址,每个人的不一样。
在电脑的浏览器访问的话哪个都行,但在手机或模拟器访问的话需要用第二个带 ip 地址的,且要保证手机跟电脑连接同一个 wifi 或在同一网段。
注意:这里用的是 vue-cli 3.0,运行命令跟 vue-cli 2.X 有所区别。详情请自行查询官方文档。
启动成功后在 Android 项目中将 http://10.0.0.188:8080/ 地址配置给 WebView 即可
1Intent intent = new Intent(getActivity(), ProgressWebviewActivity.class); 2intent.putExtra("url", "http://10.0.0.188:8080/"); 3startActivity(intent);
到此,在手机中就可以访问 Vue 项目了。
二、Android 原生调用 JS 中的方法
Android 调用 JS 有两种方式,都是通过 WebView 的方法:
webview.loadUrl()webview.evaluateJavascript()
二者区别:
loadUrl()会刷新页面,evaluateJavascript()则不会使页面刷新,所以evaluateJavascript()的效率更高
loadUrl()得不到 js 的返回值,evaluateJavascript()可以获取返回值
evaluateJavascript()在 Android 4.4 之后才可以使用
要实现的效果:
如下图,页面上有一行文字 ”哈哈“,要在 WebView 页面加载完的时候通过 Android 原生代码将这行字改为 ”我通过原生方法改变了文字“ + Android 传递过来的参数,并给 Android 返回一个字符串 ”js调用成功“。

2.1 Vue 代码
先看 Vue 中代码怎么写
1mounted() { 2 //将要给原生调用的方法挂载到 window 上面 3 window.callJsFunction = this.callJsFunction 4}, 5data() { 6 return { 7 msg: "哈哈" 8 } 9}, 10methods: { 11 callJsFunction(str) { 12 this.msg = "我通过原生方法改变了文字" + str 13 return "js调用成功" 14 } 15}
在 methods 中定义一个供 Android 调用的方法 callJsFunction(str) , 并可接收一个参数 str,然后改变页面中的文字。
如果只是在 methods 中定义方法,原生调用会找不到这个方法。所以要在页面加载的时候将方法挂载在 window 上,这样 WebView 就可以拿到此方法了。注意,这步很重要一定要写!
注意一个细节,this.callJsFunction 后面不要加括号 (),加括号相当于直接调用了。
总结起来 Vue 中要做的事情就两步:
- 在
methods中定义方法 - 在
mounted中将方法挂载在window上
2.2 Android 中代码
需要等页面加载完在 WebView 的 onPageFinished 方法中写调用逻辑,否则不会执行。
2.2.1 loadUrl() 实现
1tbsWebView.setWebViewClient(new WebViewClient() { 2 @Override 3 public boolean shouldOverrideUrlLoading(WebView view, String url) { 4 view.loadUrl(url, headerMap); 5 return true; 6 } 7 8 @Override 9 public void onPageFinished(WebView webView, String s) { 10 super.onPageFinished(webView, s); 11 //安卓调用js方法。注意需要在 onPageFinished 回调里调用 12 tbsWebView.post(new Runnable() { 13 @Override 14 public void run() { 15 tbsWebView.loadUrl("javascript:callJsFunction('soloname')"); 16 } 17 }); 18 } 19 }); 20 } 21});
如果不需要传参数,把参数去掉即可 tbsWebView.loadUrl("javascript:callJsFunction()");
2.2.2 evaluateJavascript() 实现
其他地方跟loadUrl()一样,只是把 tbsWebView.loadUrl("javascript:callJsFunction('soloname')"); 替换掉
1@Override 2public void onPageFinished(WebView webView, String s) { 3 super.onPageFinished(webView, s); 4 //安卓调用js方法。注意需要在 onPageFinished 回调里调用 5 tbsWebView.post(new Runnable() { 6 @Override 7 public void run() { 8 tbsWebView.evaluateJavascript("javascript:callJsFunction('soloname')", new ValueCallback<String>() { 9 @Override 10 public void onReceiveValue(String s) { 11 Logger.d("js返回的结果: " + s); 12 } 13 }); 14 } 15 }); 16}
可以看到页面更新了,第二种方法也拿到了返回的结果。

三、JS 调用 Android 原生方法
对于JS调用Android代码的方法有3种:
- 通过
WebView的addJavascriptInterface()进行对象映射 - 通过
WebViewClient的shouldOverrideUrlLoading()方法回调拦截 url - 通过
WebChromeClient的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt()消息
对比: 第一种最简洁,但在 Android 4. 2 以下存在漏洞;第二种和第三种使用复杂,但不存在漏洞问题。
由于目前的设备系统版本基本都在 4.2 以上,所以用第一种就可以了,简单快捷。时间有限本文只实现第一种,第二种和第三种就不实现了,想了解的可以参考 这篇文章 。
3.1 效果展示
要实现的效果就是点击 H5 页面上的按钮,弹出 Android 原生的 Toast

3.2 Vue 代码
1methods: { 2 showAndroidToast() { 3 $App.showToast("哈哈,我是js调用的") 4 } 5}
在 methods 中定义方法 showAndroidToast() , 点击页面上按钮 "调用Android原生Toast" 时调用。
3.3 Android 代码
新建类 JsJavaBridge
1public class JsJavaBridge { 2 3 private Activity activity; 4 private WebView webView; 5 6 public JsJavaBridge(Activity activity, WebView webView) { 7 this.activity = activity; 8 this.webView = webView; 9 } 10 11 @JavascriptInterface 12 public void onFinishActivity() { 13 activity.finish(); 14 } 15 16 @JavascriptInterface 17 public void showToast(String msg) { 18 ToastUtils.show(msg); 19 } 20}
然后通过 WebView 设置 Android 类与 JS 代码的映射
tbsWebView.addJavascriptInterface(new JsJavaBridge(this, tbsWebView), "$App");
这里将类 JsJavaBridge 在 JS 中映射为了 $App,所以在 Vue 中可以这样调用 $App.showToast("哈哈,我是js调用的")。
以上就是 Android 与 JS 的互相调用。
