Android之深入WebView
WebView
目录
- 思维导图
- WebView 的基本使用
- WebView
- WebSettings
- WebViewClient
- WebChromeClient
- WebView 与 JS 交互
- Android 去调用 JS 代码
- JS 调用 Android 代码
- WebView 常见问题汇总
- WebView 优化
- 参考
思维导图
基本使用
WebView 是一个基于 webkit 引擎,展示 web 页面的空间。WebView 在低版本和高版本采用了不同的 webkit 内核版本,4.4 ( API 19 ) 之后直接使用了 Chrome。
WebView 类
/*** 返回键后退网页* 如果又重写了 onBackPressed 方法,只会回调 onKeyDown*/@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) {mWebView.goBack();return true;}return super.onKeyDown(keyCode, event);}mWebView.onPasue();//清除缓存数据mWebView.clearCache(true); //清除缓存mWebView.clearHistory(); //清除浏览记录mWebView.clearFormData(); //清除自动填充的表单数据
WebSetting 类
对 WebView 进行配置和管理。
private void setWebViewSettings(WebView webView){WebSettings webSettings=webView.getSettings();webSettings.setJavaScriptEnabled(true); //支持 JSwebSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过 JS 打开新的窗口//设置自适应屏幕webSettings.setUseWideViewPort(true);webSettings.setLoadWithOverviewMode(true);webSettings.setLoadsImagesAutomatically(true); //设置自动加载图片webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE); //不使用缓存//...}
WebViewClient 类
处理各种通知和请求事件等等。
//在当前 WebView 打开页面,而不是系统浏览器
//如果不需要转发处理,只需要传递一个 WebViewClent 实例,根本不需要重写 shouldOverrideUrlLoading 方法
public class MyWebViewClient extends WebViewClient {private Context mContext;public MyWebViewClient(Context context) {mContext = context;}@Overridepublic boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {//当前 WebView 处理if (request.getUrl().getHost().equals("https://www.example.com")) {return false;}//如果需要转发处理mContext.startActivity(new Intent(Intent.ACTION_VIEW, request.getUrl()));return true;}@Overridepublic void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {switch (error.getErrorCode()){case WebViewClient.ERROR_CONNECT: //连接失败view.loadUrl("file:///android_asset/error.html");break;}}@Overridepublic void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {handler.proceed(); //等待证书响应 //handler.cancel(); //挂起连接 默认行为}
}//使用WebViewClient
mWebView.setWebViewClient(new MyWebViewClient(MainActivity.this));
WebChromeClient 类
辅助 WebView 处理 JS 的对话框、网站标题等等。
public class MyWebChromeClient extends WebChromeClient {/*** 网页加载进度*/@Overridepublic void onProgressChanged(WebView view, int newProgress) {super.onProgressChanged(view, newProgress);}/*** 网页标题加载完毕回调*/@Overridepublic void onReceivedTitle(WebView view, String title) {super.onReceivedTitle(view, title);}/*** 拦截输入框*/@Overridepublic boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {return super.onJsPrompt(view, url, message, defaultValue, result);}/*** 拦截确认框*/@Overridepublic boolean onJsConfirm(WebView view, String url, String message, JsResult result) {return super.onJsConfirm(view, url, message, result);}/*** 拦截弹框*/@Overridepublic boolean onJsAlert(WebView view, String url, String message, JsResult result) {return super.onJsAlert(view, url, message, result);}
}//使用WebChromeClient
mWebView.setWebChromeClient(new MyWebChromeClient());
WebView 与 JS 交互
WebView 与 JS 交互分为俩种情况,一种是JS 调用 Android 代码,另一种是JS 调用 Android 方法。
Android 调用 JS 代码
- webView.loadUrl(url)
- webView.evaluateJavascript()
首先选准备一个静态文件:
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>Title</title><script>function callJS(){alert("Android调用了 JS 的 callJS() 方法");}</script><p3>WebView 与 JS 交互!</p3>
</head>
</html>
第一种方式:loadUrl()
mWebView.loadUrl("javascript:callJS()");mWebView.setWebChromeClient(new WebChromeClient(){@Overridepublic boolean onJsAlert(WebView view, String url, String message, final JsResult result) {AlertDialog dialog=new AlertDialog.Builder(WebViewContactActivity.this).setTitle("Title").setPositiveButton("确认", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {result.confirm();}}).setCancelable(false).setMessage(message).create();dialog.show();return true;}});
可以看到,WebView 只是载体,内容的渲染还的通过 WebChromeClient 承载。
第二种方式:evaluateJavascript()
mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {@Overridepublic void onReceiveValue(String value) {//JS 返回的结果Toast.makeText(WebViewContactActivity.this, "value " + value, Toast.LENGTH_SHORT).show();}});
只是把上面的 loadUrl 换成 evaluateJavascript 方法而已。但是这种方法比第一种方式效率高,因为该方法的执行不会使页面刷新。
两种方法的对比:
调用方式 | 优点 | 缺点 | 使用场景 |
---|---|---|---|
loadUrl | 方便简洁 | 效率低 | 不需要获取返回值,对性能要求较低时 |
evaluatedJavascript | 效率高 | 向下兼容性差( API > 19 ) | API > 19 |
当然也可以通过 Build.VERSION 来进行判断执行。
JS 调用 Android 代码
- 通过 WebView.addJavascriptInterface 进行对象映射
- 通过 WebViewClient.shouldOverrideUrlLoading 方法回调拦截 url
- 通过 WebChromeClient 的 onJsAlert、onJsConfirm、onJsPrompt 方法回调拦截 JS 对话框 alert、confirm、prompt 消息
第一种方式:WebView.addJavascriptInterface 进行对象映射
首先先准备好资源文件,用于模拟 WebView 加载的网页:
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>Demo</title><script>function callAndroid(){test.hello("js调用了android中的hello方法");}</script>
</head>
<body>
<p2>JS 调用 Android 方法</p2>
<button type="button" id="button1" onclick="callAndroid()">点击按钮调用 Android 的 hello 方法</button>
</body>
</html>
然后定义一个 JS 对象映射关系的 Android 类:
public class JSObject extends Object {private Context mContext;public JSObject(Context context) {mContext = context;}@JavascriptInterfacepublic void hello(String msg){Toast.makeText(mContext, "JS 调用了 Android 的 hello 方法", Toast.LENGTH_SHORT).show();}
}
最后就是通过 WebView 设置 Android 类与 JS 代码的映射:
mWebView.loadUrl("file:///android_asset/js_to_android.html");
mWebView.addJavascriptInterface(new JSObject(this),"test");
第二种方式:WebViewClient.shouldOverrideUrlLoading 方法回调拦截 url
Android 通过 WebViewClient 的回调方法 shouldOverrideUrlLoading 拦截 url,解析该 url 协议,如果检测到是预先约定好的协议,就调用 Android 相应的方法。
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>Demo</title><script>function callAndroid(){document.location = "js://webview?arg1=2333&arg2=222";}</script>
</head>
<body>
<p2>JS 调用 Android 方法</p2>
<button type="button" id="button1" onclick="callAndroid()">点击按钮调用 Android 的方法</button>
</body>
</html>
mWebView.loadUrl("file:///android_asset/js_call_android.html");mWebView.setWebViewClient(new WebViewClient(){@Overridepublic boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {if ("js".equals(request.getUrl().getScheme())){if ("webview".equals(request.getUrl().getAuthority())){Toast.makeText(WebViewContactActivity.this, "JS 调用 Android 方法,参数一为:"+request.getUrl().getQueryParameter("arg1"), Toast.LENGTH_SHORT).show();}return true;}return super.shouldOverrideUrlLoading(view, request);}});
第三种方式:通过 WebChromeClient 的 onJsAlert、onJsConfirm、onJsPrompt 方法回调拦截 JS 对话框的消息
这里只示例 onJsPrompt 的回调,因为这个方法可以返回任意类型的值。
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>Demo</title><script>function callAndroid(){var result=prompt("js://demo?arg1=111&arg2=222");alert("demo " + result);}</script>
</head>
<body>
<p2>JS 调用 Android 方法</p2>
<button type="button" id="button1" onclick="callAndroid()">点击按钮调用 Android 的方法</button>
</body>
</html>
mWebView.loadUrl("file:///android_asset/js_call_android_demo.html");mWebView.setWebChromeClient(new WebChromeClient(){@Overridepublic boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {Uri uri=Uri.parse(message);if ("js".equals(uri.getScheme())){if ("demo".equals(uri.getAuthority())){result.confirm("JS 调用了 Android 的方法");}return true;}return super.onJsPrompt(view, url, message, defaultValue, result);}});
三种方式的比较:
调用方式 | 优点 | 缺点 | 使用场景 |
---|---|---|---|
WebView.addJavascriptInterface 对象映射 | 方便简洁 | Android 4.2 一下存在漏洞 | Android 4.2 以上相对简单的应用场景 |
WebViewClient.shouldOverrideUrlLoading 回调拦截 | 不存在漏洞 | 使用复杂,需要协议约束 | 不需要返回值情况下 |
WebChormeClient.onJsAlert / onJsConfirm / onJsPrompt 方法回调拦截 | 不存在漏洞 | 使用复杂,需要协议约束 | 能满足大多数场景 |
WebView 常见问题
WebView 销毁
@Overrideprotected void onDestroy() {super.onDestroy();if (mWebView != null) {mWebView.loadDataWithBaseURL("", null, "text/html", "utf-8", null);mWebView.clearHistory();((ViewGroup) mWebView.getParent()).removeView(mWebView);mWebView.destroy();mWebView = null;}}
Android P 阻止加载任何 http 的请求
Mainfest 中加入:
android:usesCleartextTraffic="true"
Android 5.0 之后 WebView 禁止加载 http 与 https 混合内容
if (Build.VERSION.SDK_INT>Build.VERSION_CODES.LOLLIPOP){mWebView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);}
WebView 开启硬件加速导致的问题
比如不能打开 PDF,播放视频花屏等等。
关闭硬件加速,或者直接用第三方库吧。
WebView 优化
给 WebView 加一个加载进度条
重写 WebChromeClient 的 onProgressChanged 方法。
提高 HTML 网页加载速度,等页面 finsh 在加载图片
public void int () {if(Build.VERSION.SDK_INT >= 19) {webView.getSettings().setLoadsImagesAutomatically(true);} else {webView.getSettings().setLoadsImagesAutomatically(false);} }
自定义 WebView 错误页面
重写 WebViewClient 的 onReceivedError 方法。
参考
大牛总结的非常到位,非常值得学习和借鉴。https://www.jianshu.com/p/b9164500d3fb
Android之深入WebView相关推荐
- android动态设置错误页面,Android中替换WebView加载网页失败时的页面
我们用webView去请求一个网页链接的时候,如果请求网页失败或无网络的情况下,它会返回给我们这样一个页面,如下图所示: 上面这个页面就是系统自带的页面,你觉得是不是很丑?反正小编本人觉得非常丑,很难 ...
- android学习之WebView
2019独角兽企业重金招聘Python工程师标准>>> WebView是android.webkit包下的一个组件,能用来显示网页. WebView默认是不带地址栏和加进度条的,单单 ...
- Android开发之WebView的开发使用(源代码分享)
如果我们想提供一个web应用程序(或只是一个网页)作为客户端应用程序的一部分,我们可以使用WebView.WebView类是Android的视图类的扩展,它允许您显示web页面的一部分活动布局.担它不 ...
- 解决 android 高低版本 webView 里内容 自适应屏幕的终极方法
解决 android 高低版本 webView 里内容 自适应屏幕的终极方法 参考文章: (1)解决 android 高低版本 webView 里内容 自适应屏幕的终极方法 (2)https://ww ...
- Android中脱离WebView使用WebSocket实现群聊和推送功能
WebSocket是Web2.0时代的新产物,用于弥补HTTP协议的某些不足,不过他们之间真实的关系是兄弟关系,都是对socket的进一步封装,其目前最直观的表现就是服务器推送和聊天功能.更多知识参考 ...
- android 代码浏览,Webview实现android简单的浏览器实例代码
WebView是Android中一个非常实用的组件,它和Safai.Chrome一样都是基于Webkit网页渲染引擎,可以通过加载HTML数据的方式便捷地展现软件的界面,下面通过本文给大家介绍Webv ...
- Android中获取WebView加载的html中console.log输出的内容
场景 Android中使用WebView加载本地html并支持运行JS代码和支持缩放: Android中使用WebView加载本地html并支持运行JS代码和支持缩放_BADAO_LIUMANG_QI ...
- Android中的webview详细使用
webview向html传递参数 方式一 通过 cookie传参 CookieSyncManager.createInstance(this);CookieManager cookieManager ...
- Android 8.0学习 (36)---Android 8.0 WebView 拍照、简易预览、二维码扫描 各种问题解决
Android 8.0 WebView 拍照.简易预览.二维码扫描 各种问题解决 项目用到了WebView包装HTML5做成app使用,其中有页面用到了二维码和拍照上传功能.本人从未做过android ...
最新文章
- vue——props的两种常用方法
- 使用JAVA建立稳定的多线程服务器
- HTML 自学笔记(HTML框架+表单设计)
- windows下的正向shell
- android数据持久化存储(2)
- 【剑指offer】_17正则表达式的匹配
- 顺序查找(Sequential Search)
- 以前看过一个压缩过的.exe,运行会播放长达半小时的动画,却只有60KB,个人认为其中的原理...
- java基础环境搭建_java基础环境搭建
- 魔力服务器修改器,魔力宝贝修改器
- VSCODE 远程编译调试ARM开发板
- Ubuntu 切换谷歌拼音
- 淘宝客订单查询API参数说明
- Word里表格跨页时自动断开,表格后留有空白部分,未布满整页,如何操作让表格上下页均匀布满?
- 大数据项目之电商数仓DataX、DataX简介、DataX支持的数据源、DataX架构原理、DataX部署
- 计算机格式化什么意思,格式化硬盘是什么意思?怎么格式?格式了有什么用?会有什么后果?...
- 现代人遇到鸿蒙碎片,原来我是盖世奶爸-第126章 虚空之门是鸿蒙鼎碎片?
- 杨辉三角(C语言实现)
- 服务器硬盘1t等于多少g,1t硬盘实际上等于多少个g?
- oracle增加表空间文件
热门文章
- 凌晨一点的粤海街道对抗来自美国的力量|湾区人工智能
- c语言电子地图程序,C语言 电子地图信息
- mimo-ofdm无线通信技术及matlab实现_智芯文库 | FPGA无线通信课程连载——扰码的原理及实现...
- iPhone SE 3钢化膜已上架海外市场:4.7英寸屏 Home键得到保留
- iPhone13真香了?苹果官网被抢崩了,连夜补货!粉色或成爆款..
- 格力电器上半年净利94.57亿元,同比增长48.64%
- 三星电子与索尼在CMOS图像传感器市场份额差距缩小
- 微信又有大更新!新增多款铃声、腾讯电子签等功能
- 有用户反映小米手机充电变慢,官方回应:天气过热
- 索尼PS5国行版本周开售 后期将推全配色DualSense手柄