android 添加js对象吗,Android和JS的交互_与漁的博客-程序员秘密

技术标签: android 添加js对象吗  

现在很多App为了降低开发成本和维护成本,都会内置Web网页,在安卓端是通过WebView来实现的,这就要求我们开发人员具备Android和JS交互的开发能力。

我将通过这篇文章来记录我的学习历程,在学习过程中我还是通过一个demo来加深理解,下面先贴上效果图:

3e0bfc87fb75

安卓与js的交互

效果图分别展示了js调用安卓方法的三种效果以及安卓调用js方法的两种效果,下面我把这五个方法拆开来单个学习理解。

一、先介绍一下安卓调用js方法的两种实现方式 :

1、通过webview对象调用方法loadUrl(),这样可以实现安卓调用js的方法;

2、通过webview对象调用方法evaluateJavascript(),实现安卓调用js方法。

下面从代码来具体看这两种方法的实现过程:

先贴上html文件:

安卓与js交互

function callJS1(){

alert("安卓调用JS中的callJs方法");

}

这是一个webview

这里为了代码看起来清晰明了,只放了需要的部分。代码中只放了一个功能供安卓调用。下面是安卓端的代码:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private WebView mWebView;

private Button mBtn1,mBtn2;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

initView();

configWebview();

}

@SuppressLint("SetJavaScriptEnabled")

private void configWebview() {

WebSettings settings = mWebView.getSettings();

//允许与js交互

settings.setJavaScriptEnabled(true);

//允许js弹窗

settings.setJavaScriptCanOpenWindowsAutomatically(true);

//加载html文件

mWebView.loadUrl("file:///android_asset/javascript.html");

mWebView.setWebChromeClient(new WebChromeClient(){

//这里的参数message就是html文件中callJS1()方法下alert中的文本

@Override

public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {

//创建一个弹窗

AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);

builder.setTitle("安卓与JS交互");

builder.setMessage(message);

builder.setPositiveButton("确认", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

result.confirm();

}

});

builder.setCancelable(false);

builder.create().show();

return true;

}

}

private void initView() {

mWebView = findViewById(R.id.webview);

mBtn1 = findViewById(R.id.btn1);

mBtn2 = findViewById(R.id.btn2);

mBtn1.setOnClickListener(this);

mBtn2.setOnClickListener(this);

}

@Override

public void onClick(View v) {

switch(v.getId()){

case R.id.btn1:

//通过loadUrl()方法调用JS的方法

getMethodByLoadUrl();

break;

}

}

private void getMethodByLoadUrl() {

mWebView.post(new Runnable() {

@Override

public void run() {

//这种方法调用js的方法没有返回值

mWebView.loadUrl("javascript:callJS1()");

}

});

}

}

安卓和js交互的中间桥梁就是安卓中的控件WebView,其对象一边绑定html文件,一边和安卓系统交互,这样就连接起了安卓和js。

通过WebView的对象调用方法getSettings()获取WebSettings对象,从对象名称就能看出这个类是来设置WebView一些属性的:

WebSettings settings = mWebView.getSettings();

拿到WebSettings对象后,通过以下代码设置安卓系统和js交互的权限:

settings.setJavaScriptEnabled(true);

webview中经常有一些弹窗,我们可以通过以下代码来设置js弹窗的权限:

settings.setJavaScriptCanOpenWindowsAutomatically(true);

WebView是一个View,我们就可以加载之前写好的html文件,WebView可以自动完成对页面的渲染:

mWebView.loadUrl("file:///android_asset/javascript.html");

我这里是加载的工程下assets文件下的一个本地html文件,在实际开发中将url更换成远程的就可以。

在这个方法中因为没有去获取返回值,所以设置了一个弹窗来检验安卓调用js方法的结果,所以在设置WebView属性的时候设置了同意js弹窗的权限,即settings.setJavaScriptCanOpenWindowsAutomatically(true);,这里WebView只是一个View,一扇窗户(载体),里面的窗花(弹窗)需要我们自己去定义,WebView给我们提供了方法去处理js中弹窗,就是setWebChromeClient()方法,创建弹窗的方法就是原生安卓的方法,下面贴上代码:

mWebView.setWebChromeClient(new WebChromeClient(){

//这里的参数message就是html文件中callJS1()方法下alert中的文本

@Override

public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {

//创建一个弹窗

AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);

builder.setTitle("安卓与JS交互");

builder.setMessage(message);

builder.setPositiveButton("确认", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

result.confirm();

}

});

builder.setCancelable(false);

builder.create().show();

return true;

}

}

好了,以上就是安卓调用js方法的第一种方式,用WebView提供的方法loadUrl()实现。

由于第一种方法存在一个缺点就是,安卓无法高效的获取到返回值,所以在Android4.4以后安卓系统提供了第二种方法,就是用WebView提供的方法evaluateJavaScript()来实现安卓调用js的方法,这种方法能直接获取到返回值,相较于第一种比较高效,下面来看看第二种方法的实现:

html部分代码:

function callJS2(){

return "js返回的数据";

}

这部分js功能中,我只返回了一个值,目的就是校验第二种方法获取返回值。

安卓端部分代码:

mWebView.evaluateJavascript("javascript:callJS2()", new ValueCallback() {

@Override

public void onReceiveValue(String value) {

//js返回值处理

tipString(value);

}

});

从代码中看出,第二种方法传入了两个参数,第一个参数对应js中的方法,第二个参数是一个回调对象,并且重写了一个方法,方法中包含一个String类型参数,这个参数就是js方法中返回的值。

上面学习了安卓调用js方法的两种方式,下面做个总结:

第一种方法比较方便简洁,但是获取返回值比较繁琐,需要js再去调用安卓的方法将返回值传过来,这样效率很低;

第二种方法能够获取到js的返回值,但是只支持Android4.4以上的设备,向下兼容性比较差。

综于以上总结,在实际开发中 ,为了兼容各个版本,我们可以在Android4.4以前的系统使用方法一,在4.4以上的用方法二。

二、学习完了安卓调用js的方法,下面来学习js调用安卓的方法,先简单介绍实现js调用安卓方法的三种方式:

`1、通过WebView对象调用方法addJavascriptInterface()将安卓对象映射成一个字符串,这样就可以在js中通过这个字符串调用安卓中的方法;

2、安卓端通过WebViewClient的shouldOverrideUrlLoading ()方法回调拦截url,然后解析url的协议,判断是否和预先约定好的一致,做出相应的操作;

3、安卓端通过WebChromeClient的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt()消息.

下面来逐个学习,先贴上html文件 :

安卓与js交互

function callAndroid1(){

android.test("js调用了安卓的test方法");

}

function callAndroid2(){

document.location="js://webview?name=张三&age=24";

}

function callAndroid3(){

var result=prompt("js://android?name=李四&age=24");

alert(result);

}

这是一个webview

点击调用安卓的方法1

点击调用安卓的方法2

点击调用安卓的方法3

代码中定义了三个js方法,分别是callAndroid1()、callAndroid2()和callAndroid3(),还有三个按钮,点击的时候分别去调用三个方法,下面看看安卓端的代码是怎么实现js和安卓的交互的:

首先,第一个方法是映射一个安卓对象,所以需要先创建一个类,里面包含供js调用的方法:

public class Android {

private Context context;

Android(Context context) {

this.context = context;

}

@JavascriptInterface

public void test(String msg){

Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();

}

}

建好了类,定义好了供js调用的方法后,通过如下代码完成安卓对象的映射:

mWebView.addJavascriptInterface(new Android(this),"android");

以上代码将安卓对象映射成android,所以在html文件中就有android.test("js调用了安卓的test方法");,到了这就完成了js对安卓方法的调用。

不过这里需要注意一点:这种方法在Android4.2以前存在漏洞,就是映射之后这个类中所有的方法都会暴漏在js中,当有些方法我们是不希望js能够调用到的时候,这个时候就存在安全威胁,所以在4.2以后 ,安卓系统让能够被js调用的方法加上注释@JavascriptInterface。

学习完了第一种方式,下面学习第二种方式,html文件和第一种差不多,上面已经给出,这里直接贴上安卓端的处理部分代码:

mWebView.setWebViewClient(new WebViewClient(){

@Override

public boolean shouldOverrideUrlLoading(WebView view, String url) {

Uri uri = Uri.parse(url);

if (uri.getScheme() != null && uri.getScheme().equals("js")) {

if (uri.getAuthority() != null && uri.getAuthority().equals("webview")) {

Set names = uri.getQueryParameterNames();

// tip(names);

//调用Android中的方法

tipString(uri.getQueryParameter("name"));

}

//处理完了记得return 不然会出错

return true;

}

return super.shouldOverrideUrlLoading(view, url);

}

});

代码中WebViewClient通过shouldOverrideUrlLoading拦截url,并转换成uri,然后获取url的协议,即uri.getScheme()和uri.getAuthority(),然后判断是否和事先约定好的一致,当一致的时候再来做出相应的操作,在这里我是将拼接在url的参数取出来并显示在屏幕上。

上面就是第二种方式的实现过程,他不存在第一种方法那样的漏洞,但是也存在一个缺点 ,因为这种方法是通过拦截url,然后判断协议的方式来调用安卓方法的,在js将url传递过来后,安卓就失去了和js的通信,所以它也存在和安卓通过loadUrl()调用js方法一样的缺点,就是无法高效获取返回值,要想取得返回值,只能让安卓再去调用js的方法将返回值传递给js,这样效率明显不理想,所以在一些不需要返回值的交互场景中推荐这种方法 。

接下来学习第三种方式,这里只是学习了输入框,另外的警告框和确认框差不多的。

安卓端的处理部分代码:

@Override

public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {

Uri uri = Uri.parse(message);

if (uri.getScheme() != null && uri.getScheme().equals("js")) {

if (uri.getAuthority() != null && uri.getAuthority().equals("android")) {

//通过这个方法将安卓中的数据返回到js中去

result.confirm("JS调用安卓的方法");

}

//处理完了记得return 不然会出错

return true;

}

return super.onJsPrompt(view, url, message, defaultValue, result);

}

这种方法和第二种差不多,都是判断url的协议,然后根据判断的结果做出相应的操作,它和第二种方法的区别就是第三种方法js能够获取到返回值,因为js中警告框、确认框和输入框这三种弹框都有返回值,并且都能监听到选择或是输入的结果。这也使得第三种方法能满足大多数场合。

好了 ,以上就是对js调用安卓方法三种实现方式的学习,这里总结以下:

第一种方法方便简洁,但在Android4.2以前存在漏洞,4.2以后的场合可以 考虑这种方法;

第二种方法不存在漏洞了,但是url的协议判断过程相对来说复杂,而且获取返回值也比较复杂,不需要返回值的场合可以考虑用这种方法;

第三种方法不存在漏洞,判断url协议和第二种方法一样,但这种方法能获取到返回值,所以第三种方法能满足大多数场合。

以上就是本人对Android和JS交互的学习,希望发现文中有不当之处的朋友们能够指正。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_32659481/article/details/117323096

智能推荐

Jenkins shell 工作自动化脚本_AMing_阿明的博客-程序员秘密

build kit and lib jar编译本地机器上的 Android 融云 SDK Jar 包 , 包含 Rong_IMKit.jar 和 Rong_IMLib.jar , 输出产物在本机 xx/localjenkins/output/cd /Users/zhouxuming/Documents/ReviewRongCloudSrc/android-workspacegit c...

NES 6502_IRQ_CRASH的博客-程序员秘密

.686 ; create 32 bit code .mmx .xmm .model flat, stdcall ; 32 bit memory model option casemap :none ; case sensitive ; =================

RhinoPython寻找曲面法向量_Archi_nan的博客-程序员秘密

#coding:utf-8import rhinoscriptsyntax as rsdef NormalSrf(Srf,intU,intV): Udomain=rs.SurfaceDomain(Srf,0) Vdomain=rs.SurfaceDomain(Srf,1) stepU=(Udomain[1]-Udomain[0])/intU stepV=(Udomain[1]-Udomain[0])/intV ptMtx={} for i in .

C++ STL IO流 与 Unicode (UTF-16 UTF-8) 的协同工作_shuixin536的博客-程序员秘密

凡用到文件读写,输入输出,就得和编码、Unicode 打交道。这系列实验来测试一下 C++ STL 的 IO流 对 ANSI 编码、Unicode 编码的支持特性,看能否找到一个自动识别编码,自动转码的解决方案。从基础开始,一步一步来: 平台 Win32 XP sp3 + VS2008. (+ Boost 1.36.0) 实验 01:#include#i

ooad  _iteye_6713的博客-程序员秘密

OOAD(Object Orient Analysis Design,面向对象的分析和设计,面向对象分析与设计)是现代软件企业广为采用的一项有效技术。OOAD方法要求在设计中要映射现实世界中指定问题域中的对象和实体,例如:顾客、汽车和销售人员等。这就需要设计要尽可能地接近现实世界,即以最自然的方式表述实体。所以面向对象技术的优点即为能够构建与现实世界相对应的问题模型,并保持他们的结构、关系和行为为...

PowerBI 报表服务器刷新失败自动重刷并邮件通知_黄饱饱_bao的博客-程序员秘密_powerbi邮件推送报表

前言:大家好,我是小小大世界,初来乍到,作为一名BI工作者,一直想着通过某种方式记录自己成长的点点滴滴,今天静下心来,开始写一些自己工作中的经验。正文:前几天看了几篇文章,提到了如何使用报表服务器数据库创建触发器,在报表刷新失败时自动发邮件通知,心里想着这个功能挺实用的,不需要整点去看报表是否成功刷新,或者后台查报表的刷新日志。不过进一步思考了一下,大家都知道,报表服务器报表多了之后,若都是导入模式制作的报表,难免要定时刷新,但多张报表刷新时间相近,就经常出现刷新失败的情况,以往是同一张报表

随便推点

数学建模—多元回归分析_「已注销」的博客-程序员秘密_数学建模多元回归分析

title: 数学建模—多元回归分析tags:建模EverydayOneCat木星全貌????知识点1.笔记在了接受域中,接受X为0的假设,X对外没有比较显著的线性关系。2.知识点补充多元回归模型:含两个以上解释变量的回归模型多元线性回归模型的假设:解释变量Xi 是确定性变量,不是随机变量解释变量之间互不相关,即无多重共线性随机误差项不存在序列相关关系随机误差项与解释变量之间不相关随机误差项服从0均值、同方差的正态分布例题1.多元线性回归某品种水稻糙米含镉

【open Judge】c语言 20:求一元二次方程的根_Irene_ljr的博客-程序员秘密

20:求一元二次方程的根查看提交统计提问总时间限制: 1000ms 内存限制: 65536kB描述利用公式x1 = (-b + sqrt(b*b-4*a*c))/(2*a), x2 = (-b - sqrt(b*b-4*a*c))/(2*a)求一元二次方程ax2+ bx + c =0的根,其中a不等于0。输入输入一行,包含三个浮点数a

Java动态调用类方法实例_bailang71的博客-程序员秘密

一.概述       在前面已经介绍了关于Java.lang.reflect.*包中的一些基本的知识。这里通过对上文提供的一个实例进行实际编程并测试。       这里分别使用了两个包中的两个类。所用到的包及包中的文件列表如下:testclass包:该包中包含一个编译过的类class1,该类只有一个方法add。dyn_callmethod包:该包中包含一个已编译的类callclass,该类包含做为

CS224N学习笔记(1)_Neways谭的博客-程序员秘密

CS224N学习笔记(1)欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入欢迎使...

2019年企业新增长 容智RPA机器人让你领会办公新时代_容智RPA_爱博特的博客-程序员秘密

雇佣“机器人员工”似乎是一件美妙的事。它不知疲倦,7x24小时孜孜不倦的工作。它效率极高,一小时内完成人工需要花两天才能完成的工作,几乎不出错。它不会因为心情影响工作效率,也不会和其他同事聊天,不暗中偷懒,不计较年终奖……不管怎么看,它都是一位受老板喜欢的员工。在使用机器人后,某银行过去对公开户时间从原来的23天降低到10分钟,个人房屋贷款发放流程从原来的3周缩短到几个小时。有公司的采购部每年...

webpack、Babel 使用中报的错误总结_心之语歌的博客-程序员秘密

标题webpack、Babel 使用中报的错误总结vue-cli的配置vue-cli的配置 Babel 中运行cnpm run dev报的错以下是报错信息Using removed Babel 5 option: foreign.modules -Use the corresponding module transform plugin in the `plugins` option解决方法是添加.babelrc文件,内容填写{ "presets": [ [