Android webview 与 js(Vue) 交互

待兔
• 阅读 2401

js 与原生交互分为两种情况:js 调用原生方法,原生调用 js 方法。

本文将对这两种情况分别讲解,H5 端用 vue 实现。

一、前期准备(Vue项目准备)

本文的 H5 端用Vue 实现,所以在正式开始前先把 Vue 项目环境准备好。

项目写好后,执行 npm run serve 命令启动项目,启动成功后会在命令行看到两个地址:

Android webview 与 js(Vue) 交互

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 的方法:

  1. webview.loadUrl()
  2. webview.evaluateJavascript()

二者区别:

  1. loadUrl() 会刷新页面,evaluateJavascript() 则不会使页面刷新,所以 evaluateJavascript() 的效率更高

  2. loadUrl() 得不到 js 的返回值,evaluateJavascript() 可以获取返回值

  3. evaluateJavascript() 在 Android 4.4 之后才可以使用

要实现的效果:

如下图,页面上有一行文字 ”哈哈“,要在 WebView 页面加载完的时候通过 Android 原生代码将这行字改为 ”我通过原生方法改变了文字“ + Android 传递过来的参数,并给 Android 返回一个字符串 ”js调用成功“。

Android webview 与 js(Vue) 交互

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 中要做的事情就两步:

  1. methods 中定义方法
  2. mounted 中将方法挂载在 window

2.2 Android 中代码

需要等页面加载完在 WebViewonPageFinished 方法中写调用逻辑,否则不会执行。

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);
                }
            });
        }
    });
} 

可以看到页面更新了,第二种方法也拿到了返回的结果。

Android webview 与 js(Vue) 交互

三、JS 调用 Android 原生方法

对于JS调用Android代码的方法有3种:

  1. 通过 WebViewaddJavascriptInterface() 进行对象映射
  2. 通过 WebViewClientshouldOverrideUrlLoading()方法回调拦截 url
  3. 通过 WebChromeClientonJsAlert()onJsConfirm()onJsPrompt()方法回调拦截JS对话框alert()confirm()prompt() 消息

对比: 第一种最简洁,但在 Android 4. 2 以下存在漏洞;第二种和第三种使用复杂,但不存在漏洞问题。

由于目前的设备系统版本基本都在 4.2 以上,所以用第一种就可以了,简单快捷。时间有限本文只实现第一种,第二种和第三种就不实现了,想了解的可以参考 这篇文章

3.1 效果展示

要实现的效果就是点击 H5 页面上的按钮,弹出 Android 原生的 Toast

Android webview 与 js(Vue) 交互

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 的互相调用。

点赞
收藏
评论区
推荐文章
blmius blmius
1年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录 问题 用navicat导入数据时,报错: 原因这是因为当前的MySQL不支持datetime为0的情况。 解决修改sql\mode: sql\mode:SQL Mode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。 全局s
Easter79 Easter79
11个月前
swap空间的增减方法
(1)增大swap空间 去激活swap交换区: #swapoff -v /dev/vg00/lvswap 扩展交换lv: #lvextend -L 10G /dev/vg00/lvswap 重新生成swap交换区: #mkswap /dev/vg00/lvswap 激活新生成的交换区: #swapon -v /dev/vg00/lvswap
Wesley13 Wesley13
11个月前
Java爬虫之JSoup使用教程
title: Java爬虫之JSoup使用教程 date: 2018-12-24 8:00:00 +0800 update: 2018-12-24 8:00:00 +0800 author: me cover: [https://img-blog.csdnimg.cn/20181224144920712](https://www.oschin
Stella981 Stella981
11个月前
KVM调整cpu和内存
一.修改kvm虚拟机的配置 1、virsh edit centos7 找到“memory”和“vcpu”标签,将 <name>centos7</name> <uuid>2220a6d1-a36a-4fbb-8523-e078b3dfe795</uuid>
Stella981 Stella981
11个月前
Python之time模块的时间戳、时间字符串格式化与转换
Python处理时间和时间戳的内置模块就有`time`,和`datetime`两个,本文先说`time`模块。 ### 关于时间戳的几个概念 * 时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。 * 时间元组(`struct_time`),包含9个元素。  `time.struct_time(tm_y
Wesley13 Wesley13
11个月前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表: **时辰** **时间** **24时制** 子时 深夜 11:00 - 凌晨 01:00 23:00 - 01 :00 丑时 上午 01:00 - 上午 03:00 01:00 - 03 :00 寅时 上午 03:00 - 上午 0
Wesley13 Wesley13
11个月前
MySQL查询按照指定规则排序
1.按照指定(单个)字段排序 select * from table_name order id desc; 2.按照指定(多个)字段排序 select * from table_name order id desc,status desc; 3.按照指定字段和规则排序 selec
Wesley13 Wesley13
11个月前
PHP中的NOW()函数
是否有一个PHP函数以与MySQL函数`NOW()`相同的格式返回日期和时间? 我知道如何使用`date()`做到这一点,但是我问是否有一个仅用于此的函数。 例如,返回: 2009-12-01 00:00:00 * * * ### #1楼 使用此功能: function getDatetimeNow() {
Wesley13 Wesley13
11个月前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
#### 背景描述 # Time: 2019-01-24T00:08:14.705724+08:00 # User@Host: **[**] @ [**] Id: ** # Schema: sentrymeta Last_errno: 0 Killed: 0 # Query_time: 0.315758 Lock_
helloworld_34035044 helloworld_34035044
2个月前
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。 uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid() 或 uuid(sep)参数说明:sep 布尔值,生成的uuid中是否包含分隔符'',缺省为