Android WebView和Js交互
现在纯原生Android开发越来越少了,现在一般App都会混合开发,其他混合的技术先不说,最常用就是WebView加载H5页面,再App客户端和Web端交互,提供一些用户信息、客户端Api等,本篇介绍WebView调用Js,Js调用Android方法的知识。
本文使用的Html文件
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>WebView</title>
<style type="text/css">
body {
background: #caff0c;
}
.btn {
line-height: 40px;
margin: 10px;
background: #cccccc;
}
#input {
margin-left: 5px;
}
</style>
</head>
<body>
<h2>WebView</h2>
<div><span>请输入要传递的数据</span><input type="text" id="input"></div>
<div id="btn"><span class="btn">点我</span></div>
<div><a href="info://info?name=wally&age=18">点我跳转链接</a></div>
<script type="text/javascript">
//5.按钮点击,调用客户端方法
var btnEle = document.getElementById("btn");
var inputEle = document.getElementById("input");
btnEle.addEventListener("click", function () {
var str = inputEle.value;
if (window.androidJs) {
window.androidJs.setValue(str);
} else {
alert("window androidJs is not found!")
}
})
//提供给客户端调用的有参Js方法,设置输入文字
var remote = function (str) {
inputEle.value = str;
}
//带返回值的Js方法,给客户端获得输入的文字
var remoteWithValue = function () {
return inputEle.value;
}
</script>
</body>
</html>
JS调用Android方法
(方式一)
1.允许WebView加载Js代码
2.编写一个提供给Web的Js接口类(方法要加上@JavascriptInterface注解)
3.给WebView添加Js接口(将接口对象挂载到Web的window下)
4.Web端调用window下的接口类对象中的Android方法
Android客户端,设置允许加载Js代码,提供Js接口类,注入到Web端的Window中。
/**
* 加载的Html位置
*/
private static final String SETUP_HTML = "file:///android_asset/index.html";
//1.允许WebView加载Js代码
mWebView.getSettings().setJavaScriptEnabled(true);
/**
* 2.编写一个提供给Web的Js接口类
*/
public class JsInterface {
private static final String TAG = JsInterface.class.getSimpleName();
private Callback mCallback;
public JsInterface(Callback callback) {
mCallback = callback;
}
@JavascriptInterface
public void setValue(String value) {
if (TextUtils.isEmpty(value)) {
return;
}
Log.d(TAG, "value: " + value);
if (mCallback != null) {
mCallback.onSetValue(value);
}
}
public interface Callback {
void onSetValue(String value);
}
}
//3.给WebView添加Js接口
mWebView.addJavascriptInterface(new JsInterface(new JsInterface.Callback() {
@Override
public void onSetValue(final String value) {
mMainHandler.post(new Runnable() {
@Override
public void run() {
mResult.setText("value: " + value);
}
});
}
}), "androidJs");
//4.加载Html
mWebView.loadUrl(SETUP_HTML);
Html中按钮点击时,Js调用客户端方法
//5.按钮点击,调用客户端方法
var btnEle = document.getElementById("btn");
var inputEle = document.getElementById("input");
btnEle.addEventListener("click", function () {
var str = inputEle.value;
//判断是否在客户端环境
if (window.androidJs) {
window.androidJs.setValue(str);
} else {
alert("window androidJs is not found!")
}
})
(方式二)
-
和客户端协商协议,以该协议加载Url,客户端WebView.setWebViewClient(),复写shouldOverrideUrlLoading()进行拦截,获取行为和参数。
//和前端协商的协议前缀
private static final String CALLBACK_SCHEME = "info://info";
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//是否拦截Url
boolean isIntercept = url.startsWith(CALLBACK_SCHEME);
//处理拦截特定前缀Url
handleUrlIntercept(url);
if (isIntercept) {
return true;
} else {
return super.shouldOverrideUrlLoading(view, url);
}
}
});
/**
* 处理拦截特定前缀Url
*/
private void handleUrlIntercept(String text) {
HashMap<String, String> paramsMap = new HashMap<>(5);
String result = text.replaceFirst(CALLBACK_SCHEME.concat("\\?"), "");
String[] paramsGroup = result.split("&");
//按组拆分bold=false
for (String groupStr : paramsGroup) {
String[] paramsKeyValue = groupStr.split("=");
//参数和值拆分
String paramsName = paramsKeyValue[0];
String paramsValue = paramsKeyValue[1];
paramsMap.put(paramsName, paramsValue);
}
final String name = paramsMap.get("name");
final String age = paramsMap.get("age");
toast("拦截Url,获取参数 -> " + "name:" + name + " age:" + age);
}
Web端,超链接加载自定义协议,客户端进行拦截
//点击超链接,加载自定义协议,客户端进行拦截
<div><a href="info://info?name=wally&age=18">点我跳转链接</a></div>
(方式三)
使用prompt,发送数据,客户端webView.setWebChromeClient,复写onJsPrompt进行拦截,获取数据。
mWebView.setWebChromeClient(new WebChromeClient() {
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
//拦截掉,回调4.4一下的Js返回值处理
OnMethodResultCallback callback = mCompatKitkatJsMethodCallbackMap.get(url);
if (callback != null) {
callback.onMethodResult(message);
mCompatKitkatJsMethodCallbackMap.remove(url);
//拦截后必须取消掉,不发送到客户端WebView,不调用也不行,会阻塞等待结果
result.cancel();
return true;
} else {
return super.onJsPrompt(view, url, message, defaultValue, result);
}
}
});
Android调用Js方法
/**
* 调用JS方法获取返回值的监听
*/
interface OnMethodResultCallback {
/**
* 返回值返回时回调
*
* @param result 函数返回值
*/
void onMethodResult(String result);
}
调用无返回值Js方法
1.Web提供Js方法
2.Android客户端调用
WebView.loadUrl(“javascript:methodName(params)”);,调用Js方法。
客户端,设置发送文字调用Js方法,设置输入内容
//调用无返回值的Js方法
mSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String str = mInput.getText().toString();
mWebView.loadUrl("javascript:if(window.remote){window.remote('" + str + "')}");
}
});
Web端提供的Js方法,设置输入内容
//提供给客户端调用,设置输入文字
var remote = function (str) {
inputEle.value = str;
}
调用有参Js方法
1.4.4以上,调用webView.evaluateJavascript(),提供一个ValueCallback获取返回值。
2.4.4一下,没有获取返回值的Api,只能使用alert,prompt,confirm。在mWebView.setWebChromeClient()中复写onJsAlert()、onJsConfirm()、onJsPrompt()拦截。
//调动有返回值的Js方法
mCallJsParamsMethod.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
final OnMethodResultCallback onCall = new OnMethodResultCallback() {
@Override
public void onMethodResult(String result) {
toast("收到调用的Js方法返回值: " + result);
}
};
if (isOvertopKitkat()) {
//4.4以上可以直接用
mWebView.evaluateJavascript("javascript:remoteWithValue();", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
onCall.onMethodResult(value);
}
});
} else {
mCompatKitkatJsMethodCallbackMap.put(SETUP_HTML, onCall);
//4.4以下,使用prompt将信息带出去,受到信息再拦截掉
mWebView.loadUrl("javascript:prompt(remoteWithValue());");
}
}
});
mWebView.setWebChromeClient(new WebChromeClient() {
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
//拦截掉,回调4.4一下的Js返回值处理
OnMethodResultCallback callback = mCompatKitkatJsMethodCallbackMap.get(url);
if (callback != null) {
callback.onMethodResult(message);
mCompatKitkatJsMethodCallbackMap.remove(url);
//拦截后必须取消掉,不发送到客户端WebView,不调用也不行,会阻塞等待结果
result.cancel();
return true;
} else {
return super.onJsPrompt(view, url, message, defaultValue, result);
}
}
});
/**
* 版本号是否大于等于4.4
*/
protected boolean isOvertopKitkat() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
}
欢迎关注我的公众号,一起进步!
本文分享自微信公众号 - Android架构师成长之路(gh_07f996f00d9b)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
2020 大前端学习路线完全指南
很高兴和大家以图文的形式见面, 众所周知,大前端统一了所有的前端,特点在于一次开发,同时适用于所有平台。大前端是 Web 统一的时代,利用 Web 不仅能开发出网站,更可以开发手机端 Web 应用和移动端应用程序。然而,对于尚在技术门外的小伙伴,网络上鲜有介绍学习路线的指导性资料。本文正是为了弥补这一不足而生的。 前端学习路线思维导图 本次的内容,我们来聊一聊大前端的学习路线。 相信对本篇文章感兴趣的读者都或多或少地对大前端感兴趣,那么在开始学习之前,我们要解决一个问题: 我适合做大前端开发吗? 我适合做大前端开发吗 时至今日,前端开发技术已经历经了多年的发展。它所支持的平台除了传统意义上的 Web 外,还包括了移动端、OTT,甚至是一些新的物联网设备。这也是其名为“大前端”的原因——它是所有前端的统称。 我们都知道,当今社会是个“看脸”的社会,前端开发技术与此息息相关。前端的特点在于一次开发,多端适用。弥补了传统开发过程中,由于各个平台使用的技术栈不同,造成了开发成本的高昂的问题。 可以说,大前端时代是 Web 统一的时代。 说到这,大家可能心里已经有数了:“原来大前端就是和用户打交...
- 下一篇
springmvc整合validation(二) @valid与@validated的区别
在上一篇中( springmvc整合validation(一) ),梳理了如何整合validation校验框架。本篇我们梳理一下@valid和@validated的区别。 在检验入参是否符合规范时,使用@Validated或者@Valid在基本验证功能上没有太多区别。但是在分组、注解地方、嵌套验证等功能上两个注解会有所不同。 1.分组校验 @Validated提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制。没有添加分组属性时,默认验证没有分组的验证属性。 使用场景举例:一个DTO类,有一个id的属性,我们希望在insert的时候id为空,在update和delete的时候,id不能为空。 本篇内容是在( springmvc整合validation(一) )的基础上实现,具体实现如下: 1.1新增groups 我们首先新增insert、update、delete三个group。注意,group必须为接口。 package com.hjj.demo.validate; public interface ValidateGroups { public in...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS7设置SWAP分区,小内存服务器的救世主
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS7安装Docker,走上虚拟化容器引擎之路
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- CentOS关闭SELinux安全模块