废话不多说直接开始
1.安卓调用JS(这里我们采用的都是本地资源)
WebSettings webSettings = webview.getSettings();
// 设置与Js交互的权限
webSettings.setJavaScriptEnabled(true);
// 设置允许JS弹窗
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
接下来就是加载与交互了。。。。。。
Android调用JS代码的方法有2种:
- 通过
WebView
的loadUrl()
- 通过
WebView
的evaluateJavascript()
第一种:使用方便 不需要获取返回值,性能低
webview.loadUrl("file:///android_asset/javascript.html");
第二种:效率高 但是只能是4.4以上使用
webview.evaluateJavascript("javascript:callJS('" + msg + "')", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
Log.e("TAG","是"+value);
}});
但是发现第二种返回值为null 网上找了白天也没有找到原因,希望大佬告诉我
为了兼容使用建议结合使用(JS返回 的值是 webview.setWebChromeClient里面)
if (version < 18) {
mWebView.loadUrl("javascript:callJS()");
} else {
mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
//此处为 js 返回的结果
}
});
webview.setWebChromeClient(new WebChromeClient() {
@Override
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
AlertDialog.Builder b = new AlertDialog.Builder(MainActivity.this);
b.setTitle("alert1");
//JS 返回来的值
b.setMessage(message);
b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//关闭窗口JS调用
result.confirm();
}
});
b.setCancelable(false);
b.create().show();
return true;
}
});
html代码如下
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Carson_Ho</title>
// JS代码
<script>
// 如果这个方法设置参数 那么他就是android 传过来的值
function callJS(msg){
alert("你好"+msg);
}
</script>
</head>
</html>
2 JS调用安卓代码
我先把html三种方式的html都贴出来
<html>
<body>
<script type="text/javascript">
<!--document.write("<h1>Hello World!</h1>")-->
function func1(str){
alert("Android调用了JS的func1方法--"+str);
return "jsjs";
}
function clickBtn(){
<!--通过这个可以给安卓传值 callByJS是接受值的方法名-->
androidObj.callByJS("JS调用了Android的方法");
}
function clickBtn2(){
<!--通过这个可以给安卓传值 location相当于拦截信息 如果一致则拦截-->
document.location = "callandroid://test?arg1=abc&arg2=202";
}
function clickBtn3(){
<!--这边会被拦截,可以取得返回值 与方法二大同小异-->
var str = prompt("callandroid://test?arg1=btn3");
alert(str);
}
</script>
<button type="button" id="btn" onclick="clickBtn()">点击调用Android代码</button>
<Br/>
<Br/>
<button type="button" id="btn2" onclick="clickBtn2()">通过拦截调用Android代码</button>
<Br/>
<Br/>
<button type="button" id="btn3" onclick="clickBtn3()">拦截prompt</button>
</body>
</html>
方式1:通过 WebView
的addJavascriptInterface()
进行对象映射
实现定义一个JS对象映射关系的Android类
public class CallByJS{
// 被JS调用的方法必须加@JavascriptInterface注解
@JavascriptInterface
public void callByJS(String str) {
Log.e("web_test",str);
}
}
将需要调用的JS代码放到src/main/assets文件夹里(查看最上面的html方法一)
在代码里通过WebView设置Android类与JS代码的映射
// 设置与Js交互的权限
webSettings.setJavaScriptEnabled(true);
private void web1() {
// 通过addJavascriptInterface()将Java对象映射到JS对象
//参数1:Javascript对象名
//参数2:Java对象名
// 通过addJavascriptInterface()将Java对象映射到JS对象
webview2.addJavascriptInterface(new CallByJS(), "androidObj");
// 加载JS代码
// 格式规定为:file:///android_asset/文件名.html
webview2.loadUrl("file:///android_asset/js.html");
}
方式2:通过shouldOverrideUrlLoading ()
拦截 url
首先在JS约定所需要的Url协议(查看html)/*约定的url协议为:js://webview?arg1=111&arg2=222*/
然后复写shouldOverrideUrlLoading ()
private void web2() {
webview2.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// 根据协议的参数进行拦截,下面拦截"callandroid://test"
// 一般根据scheme & authority判断
Uri uri = Uri.parse(url);
// 如果 scheme = callAndroid,即代表都符合约定的协议
if (uri.getScheme().equals("callandroid")) {
// 如果 authority = test,即代表都符合约定的协议
if (uri.getAuthority().equals("test")) {
// 拦截url,下面开始执行Android的方法
Toast.makeText(Main2Activity.this, "js通过拦截调用了Android的方法", Toast.LENGTH_SHORT).show();
// 可以获取参数
HashMap<String, String> params = new HashMap<>();
Set<String> paramNames = uri.getQueryParameterNames();
for (String name : paramNames) {
params.put(name, uri.getQueryParameter(name));
}
Log.e("web_test", "是"+params.toString());
}
return true;
}
return super.shouldOverrideUrlLoading(view, url);
}
});
}
方式3:通过 WebChromeClient
的onJsAlert()
、onJsConfirm()
、onJsPrompt()
方法回调拦截JS对话框alert()
、confirm()
、prompt()
消息
private void web3() {
webview2.setWebChromeClient(new WebChromeClient(){
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
return super.onJsAlert(view, url, message, result);
}
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
return super.onJsConfirm(view, url, message, result);
}
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
// 根据协议的参数进行拦截,下面拦截"callandroid://test"
// 一般根据scheme & authority判断
Uri uri = Uri.parse(message);//message是由JS的prompt()传来的
// 如果 scheme = callAndroid,即代表都符合约定的协议
if (uri.getScheme().equals("callandroid")) {
// 如果 authority = test,即代表都符合约定的协议
if (uri.getAuthority().equals("test")) {// 拦截url,下面开始执行Android的方法
// 可以获取参数
HashMap<String, String> params = new HashMap<>();
Set<String> paramNames = uri.getQueryParameterNames();
for (String name : paramNames) {
params.put(name, uri.getQueryParameter(name));
}
//将返回值返回给JS
result.confirm("拦截Prompt成功啦,传进来的参数是:"+params.toString());
}
return true;
}
return super.onJsPrompt(view, url, message, defaultValue, result);
}
});
}
参考来自 Carson_Ho
二 WebView的回退与回退刷新
1实现是回退(就是返回上一个页面而不是退出Activity)
只需要实现onKeyDown即可(代码如下)
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode==KeyEvent.KEYCODE_BACK){
if(webview3.canGoBack()){
//这个是缓存策略
webview3.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
//后退上一个页面
webview3.goBack();
return true;
}else {
//如果没有页面了关闭Acitvity
finish();
}
}
return false;
}
2解决刷新问题
其实就是改变WebView的缓存策略 一共有五个在这里就不多说了,直接上代码了
webview3.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);
view.loadUrl(url);
return super.shouldOverrideUrlLoading(view, url);
}
});
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode==KeyEvent.KEYCODE_BACK){
if(webview3.canGoBack()){
webview3.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
webview3.goBack();
return true;
}else {
finish();
}
}
return false;
}
三. 给WebView添加自定义的加载控件(我这里使用Toast)
webview3.setWebViewClient(new WebViewClient(){
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// 页面(url)开始加载
Toast.makeText(Main4Activity.this, "开始加载", Toast.LENGTH_SHORT).show();
//这个显示加载控件
}
@Override
public void onPageFinished(WebView view, String url) {
// 页面(url)完成加载
这个回调并不稳 页面加载完也不一定回调 所以换给思路
}
});
我们可以监听WebView自带的加载进度回调
webview3.setWebChromeClient(new WebChromeClient(){
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
//会触发多次
if (newProgress==100){
Toast.makeText(Main4Activity.this, "完成加载", Toast.LENGTH_SHORT).show();
这里写 控件加载完毕
}
}
});
四 WebView下拉刷新实现
SwipeRefreshLayout即可实现 xml如下
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/swrl"
tools:context=".Main5Activity">
<WebView
android:layout_width="match_parent"
android:id="@+id/webView5"
android:layout_height="match_parent">
</WebView>
</android.support.v4.widget.SwipeRefreshLayout>
代码中继续使用
swrl.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
loadurl();
}
});
webView5.setWebChromeClient(new WebChromeClient(){
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
//会触发多次
if (newProgress==100){
swrl.setRefreshing(false);
}
}
});
源码下载 点我
我只上传了xml 和代码 与html 可以复制使用