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 即可
- Intent intent = new Intent(getActivity(), ProgressWebviewActivity.class);
- intent.putExtra("url", "http://10.0.0.188:8080/");
- startActivity(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 中代码怎么写
- mounted() {
- // 将要给原生调用的方法挂载到 window 上面
- window.callJsFunction = this.callJsFunction
- },
- data() {
- return {
- msg: "哈哈"
- }
- },
- methods: {
- callJsFunction(str) {
- this.msg = "我通过原生方法改变了文字" + str
- return "js 调用成功"
- }
- }
复制代码
在 methods 中定义一个供 Android 调用的方法
callJsFunction(str)
, 并可接收一个参数 str, 然后改变页面中的文字.
如果只是在 methods 中定义方法, 原生调用会找不到这个方法. 所以要在页面加载的时候将方法挂载在 window 上, 这样 WebView 就可以拿到此方法了. 注意, 这步很重要一定要写!
注意一个细节,
this.callJsFunction
后面不要加括号 (), 加括号相当于直接调用了.
总结起来 Vue 中要做的事情就两步:
在 methods 中定义方法
在 mounted 中将方法挂载在 window 上
2.2 Android 中代码
需要等页面加载完在 WebView 的 onPageFinished 方法中写调用逻辑, 否则不会执行.
2.2.1 loadUrl() 实现
- tbsWebView.setWebViewClient(new WebViewClient() {
- @Override
- public boolean shouldOverrideUrlLoading(WebView view, String url) {
- view.loadUrl(url, headerMap);
- return true;
- }
- @Override
- public void onPageFinished(WebView webView, String s) {
- super.onPageFinished(webView, s);
- // 安卓调用 js 方法. 注意需要在 onPageFinished 回调里调用
- tbsWebView.post(new Runnable() {
- @Override
- public void run() {
- tbsWebView.loadUrl("javascript:callJsFunction('soloname')");
- }
- });
- }
- });
- }
- });
复制代码
如果不需要传参数, 把参数去掉即可
- tbsWebView.loadUrl("javascript:callJsFunction()");
- 2.2.2
- evaluateJavascript()
实现
其他地方跟 loadUrl() 一样, 只是把
tbsWebView.loadUrl("javascript:callJsFunction('soloname')");
替换掉
- @Override
- public void onPageFinished(WebView webView, String s) {
- super.onPageFinished(webView, s);
- // 安卓调用 js 方法. 注意需要在 onPageFinished 回调里调用
- tbsWebView.post(new Runnable() {
- @Override
- public void run() {
- tbsWebView.evaluateJavascript("javascript:callJsFunction('soloname')", new ValueCallback<String>() {
- @Override
- public void onReceiveValue(String s) {
- Logger.d("js 返回的结果:" + s);
- }
- });
- }
- });
- }
复制代码
可以看到页面更新了, 第二种方法也拿到了返回的结果.
三, JS 调用 Android 原生方法
对于 JS 调用 Android 代码的方法有 3 种:
通过 WebView 的
addJavascriptInterface()
进行对象映射
通过 WebViewClient 的
shouldOverrideUrlLoading()
方法回调拦截 url
通过 WebChromeClient 的 onJsAlert(),onJsConfirm(),onJsPrompt() 方法回调拦截 JS 对话框 alert(),confirm(),prompt() 消息
对比: 第一种最简洁, 但在 Android 4. 2 以下存在漏洞; 第二种和第三种使用复杂, 但不存在漏洞问题.
由于目前的设备系统版本基本都在 4.2 以上, 所以用第一种就可以了, 简单快捷. 时间有限本文只实现第一种, 第二种和第三种就不实现了, 想了解的可以参考 这篇文章 https://www.jianshu.com/p/345f4d8a5cfa .
3.1 效果展示
要实现的效果就是点击 H5 页面上的按钮, 弹出 Android 原生的 Toast
3.2 Vue 代码
- methods: {
- showAndroidToast() {
- $App.showToast("哈哈, 我是 js 调用的")
- }
- }
复制代码
在 methods 中定义方法 showAndroidToast() , 点击页面上按钮 "调用 Android 原生 Toast" 时调用.
3.3 Android 代码
新建类 JsJavaBridge
- public class JsJavaBridge {
- private Activity activity;
- private WebView webView;
- public JsJavaBridge(Activity activity, WebView webView) {
- this.activity = activity;
- this.webView = webView;
- }
- @JavascriptInterface
- public void onFinishActivity() {
- activity.finish();
- }
- @JavascriptInterface
- public void showToast(String msg) {
- ToastUtils.show(msg);
- }
- }
复制代码
然后通过 WebView 设置 Android 类与 JS 代码的映射
tbsWebView.addJavascriptInterface(new JsJavaBridge(this, tbsWebView), "$App");
复制代码
这里将类 JsJavaBridge 在 JS 中映射为了 $App, 所以在 Vue 中可以这样调用
- $App.showToast("哈哈, 我是 js 调用的")
- .
以上就是 Android 与 JS 的互相调用.
来源: https://juejin.im/post/5b7d30dfe51d4538b2046d63