在经过各种踩坑之后,才发现Webiew与本地网页间的交互实际上不难,写此文档的目的是为了今后大家在使用WebView上少走弯路,当然,这只是简单的交互方法,WebView的优化还有很长的路要走。
直接说原理显然是枯燥的,还是直接上代码吧,大家一看便知:
Android代码:
@SuppressLint("JavascriptInterface")
private void initSetting() {
WebSettings settings = mWebView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setJavaScriptCanOpenWindowsAutomatically(true);
mWebView.addJavascriptInterface(new JsInterface(), keyToWeb);
mWebView.loadUrl(htmlURL);
}
Android与JS交互的接口
private class JsInterface {
//在js中调用window.AndroidWebView.sendInfoToAndroid(name),便会触发此方法。
@JavascriptInterface
public void sendInfoToAndroid(String obj) {
Toast.makeText(MainActivity.this, "" + obj, Toast.LENGTH_SHORT).show();
}
@JavascriptInterface
public String getDataFromAndroid() {
return message;
}
}
JS代码:
function change(type) {
<!--var type = type;-->
// 很可惜未找到直接弹出Alert的方法,所以只能打Log
alert("From Web click--提示同时传出去弹吐司--"+type);
console.log("From Web click--提示同时传出去弹吐司--"+type);
window.Interface.sendInfoToAndroid(type);
}
function click_button(){
var but = window.Interface.getDataFromAndroid();
alert("From Android click -----" + but);
console.log("From Android click -----" + but);
}
Android中调用JavaScript中的函数:
mWebView.loadUrl("javascript:click_button()");
Javascript中调用Android中的方法:
window.你设置的接口中的标记.安卓对JS暴露的接口中的方法();
var but = window.Interface.getDataFromAndroid();
注意事项:
WebView设置
settings.setJavaScriptEnabled(true);
WebView暴露接口:
mWebView.addJavascriptInterface(new JsInterface(), "Interface");
第一个参数为Object类型的对象,是需要你自定义暴露给JS的接口,第二个参数为字符串类型的标志,用于android与JS互相识别。
WebView调用JS:
mWebView.loadUrl("javascript:click_button()");
JavaScript调用android:
var but = window.Interface.getDataFromAndroid();
出于安全机制考虑,要求暴露给JS的接口必须有 @JavascriptInterface 注解,以预防恶意JS注入。
实际效果:
点击网页按键一
点击控件Button–hello
从网页输出的LOG
之前研究过一段时间的JsBridge,但是时间不够,没咋看懂,有兴趣可以看一下https://github.com/lzyzsd/JsBridge
补充:
//如果webView中需要用户手动输入用户名、密码或其他,则webview必须设置支持获取手势焦点。方法如下:
mWebView.requestFocusFromTouch();
WebView WebSettings 方法说明:
//获取WebSettings
WebSettings settings = mWebView.getSettings();
//设置WebView是否支持使用屏幕控件或手势进行缩放,默认是true,支持缩放
settings.setSupportZoom(false);
//设置WebView是否通过手势触发播放媒体,默认是true,需要手势触发
settings.setMediaPlaybackRequiresUserGesture(false);
//设置WebView是否使用其内置的变焦机制,该机制集合屏幕缩放控件使用,默认是false,不使用内置变焦机制
settings.setBuiltInZoomControls(true);
//设置WebView使用内置缩放机制时,是否展现在屏幕缩放控件上,默认true,展现在控件上
settings.setDisplayZoomControls(false);
//设置WebView是否使用预览模式加载界面
settings.setLoadWithOverviewMode(false);
//设置在WebView内部是否允许访问文件,默认允许访问
settings.setAllowFileAccess(false);
//设置WebView是否保存表单数据,默认true,保存数据
settings.setSaveFormData(false);
//设置WebView中加载页面字体变焦百分比,默认100,整型数
settings.setTextZoom(100);
//设置WebView是否使用viewport,当该属性被设置为false时,加载页面的宽度总是适应WebView控件宽度;
//当被设置为true,当前页面包含viewport属性标签,在标签中指定宽度值生效,
//如果页面不包含viewport标签,无法提供一个宽度值时该方法将被使用
settings.setUseWideViewPort(false);
//设置WebView是否支持多屏窗口,参考WebChromeClient#onCreateWindow,默认false,不支持
settings.setSupportMultipleWindows(true);
//设置WebView底层的布局算法,参考LayoutAlgorithm#NARROW_COLUMNS,将会重新生成WebView布局
settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
//设置WebView标准字体库字体,默认字体“sans-serif”
settings.setStandardFontFamily("sans-serif");
//设置WebView固定的字体库字体,默认“monospace”
settings.setFixedFontFamily("monospace");
//设置WebView字体最小值,默认值8,取值1到72
settings.setMinimumFontSize(8);
//设置WebView是否加载图片资源,默认true,自动加载图片
settings.setLoadsImagesAutomatically(false);
//设置WebView是否以http、https方式访问从网络加载图片资源,默认false
settings.setBlockNetworkImage(true);
//设置WebView是否从网络加载资源,Application需要设置访问网络权限,否则报异常
settings.setBlockNetworkLoads(true);
//设置WebView是否允许执行JavaScript脚本,默认false,不允许
settings.setJavaScriptEnabled(true);
//设置WebView运行中的脚本可以是否访问任何原始起点内容,默认true
settings.setAllowUniversalAccessFromFileURLs(false);
//设置Application缓存API是否开启,默认false,设置有效的缓存路径参考setAppCachePath(String path)方法
settings.setAppCacheEnabled(true);
//设置当前Application缓存文件路径,Application Cache API能够开启需要指定Application具备写入权限的路径
settings.setAppCachePath(getApplicationContext().getCacheDir().getAbsolutePath());
//设置脚本是否允许自动打开弹窗,默认false,不允许
settings.setJavaScriptCanOpenWindowsAutomatically(true);
//设置WebView加载页面文本内容的编码,默认“UTF-8”
settings.setDefaultTextEncodingName("UTF-8");
/* 重写缓存被使用到的方法,该方法基于Navigation Type,加载普通的页面,
* 将会检查缓存同时重新验证是否需要加载,如果不需要重新加载,将直接从缓存读取数据,
* 允许客户端通过指定LOAD_DEFAULT、LOAD_CACHE_ELSE_NETWORK、LOAD_NO_CACHE、LOAD_CACHE_ONLY其中之一
* 重写该行为方法,默认值LOAD_DEFAULT
*/
settings.setCacheMode(WebSettings.LOAD_DEFAULT);
/*设置当一个安全站点企图加载来自一个不安全站点资源时WebView的行为,
*android.os.Build.VERSION_CODES.KITKAT* 默认为**MIXED_CONTENT_ALWAYS_ALLOW**,
*android.os.Build.VERSION_CODES.LOLLIPOP*默认为**MIXED_CONTENT_NEVER_ALLOW**,
取值其中之一:MIXED_CONTENT_NEVER_ALLOW、MIXED_CONTENT_ALWAYS_ALLOW、MIXED_CONTENT_COMPATIBILITY_MODE
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
settings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
WebViewClient类方法说明:
webView.setWebChromeClient(new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
//加载的进度
}
@Override
public void onReceivedTitle(WebView view, String title) {
//获取WebView的标题
}
@Override
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
return super.onJsAlert(view, url, message, result);
//Js 弹框
}
@Override
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
AlertDialog.Builder b = new AlertDialog.Builder(IllegalQueryActivity.this);
b.setTitle("删除");
b.setMessage(message);
b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
});
b.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
});
b.create().show();
return true;
}
});
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//需要设置在当前WebView中显示网页,才不会跳到默认的浏览器进行显示
return true;
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
//加载出错了
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
//加载完成
}
});
webView.setDownloadListener(new DownLoadListener());//下载监听
private class DownLoadListener implements DownloadListener {
@Override
public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
}
}
拦截网页请求URL:
示例网页html
使用WebViewClient拦截URL
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Log.i("TAG", "shouldOverrideUrlLoading----1: " + url);
if (url.startsWith("abc:")) {
Toast.makeText(MainActivity.this, "" + url, Toast.LENGTH_SHORT).show();
return true;
}
if ((url.toLowerCase().startsWith("http://")) || (url.toLowerCase().startsWith("https://"))) {
view.loadUrl(url);
return true;
}
return true;
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
Log.i("TAG", "shouldOverrideUrlLoading----2: " + request.getUrl().toString());
return super.shouldOverrideUrlLoading(view, request);
}
}
拦截回退键,让WebView返回上一页:
@Override //方法一
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override //方法二 单独处理回退键 >Android 2.0
public void onBackPressed() {
if (mWebView.canGoBack()) mWebView.goBack();
super.onBackPressed();
}
通过loadUrl( )方法更改网页显示效果,比如更改某节点样式:
mWebView.loadUrl("javascript:function setTop(){document.querySelector('#head').style.display=\"none\";}setTop();");
通过loadUrl( )向网页传入JavaScript代码,如上面代码就是增加了一个setTop()方法,方法的作用是查找html文档的head节点,更改其style属性的display值使其隐藏;最后再调用这个setTop()方法。