WebView

目录

  1. 思维导图
  2. WebView 的基本使用
    • WebView
    • WebSettings
    • WebViewClient
    • WebChromeClient
  3. WebView 与 JS 交互
    • Android 去调用 JS 代码
    • JS 调用 Android 代码
  4. WebView 常见问题汇总
  5. WebView 优化
  6. 参考

思维导图

基本使用

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 常见问题

  1. 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;}}
    
  2. Android P 阻止加载任何 http 的请求

    Mainfest 中加入:

    android:usesCleartextTraffic="true"
    
  3. Android 5.0 之后 WebView 禁止加载 http 与 https 混合内容

    if (Build.VERSION.SDK_INT>Build.VERSION_CODES.LOLLIPOP){mWebView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);}
    
  4. WebView 开启硬件加速导致的问题

    比如不能打开 PDF,播放视频花屏等等。

    关闭硬件加速,或者直接用第三方库吧。

WebView 优化

  1. 给 WebView 加一个加载进度条

    重写 WebChromeClient 的 onProgressChanged 方法。

  2. 提高 HTML 网页加载速度,等页面 finsh 在加载图片

    public void int () {if(Build.VERSION.SDK_INT >= 19) {webView.getSettings().setLoadsImagesAutomatically(true);} else {webView.getSettings().setLoadsImagesAutomatically(false);}
    }
    
  3. 自定义 WebView 错误页面

    重写 WebViewClient 的 onReceivedError 方法。

参考

大牛总结的非常到位,非常值得学习和借鉴。https://www.jianshu.com/p/b9164500d3fb

Android之深入WebView相关推荐

  1. android动态设置错误页面,Android中替换WebView加载网页失败时的页面

    我们用webView去请求一个网页链接的时候,如果请求网页失败或无网络的情况下,它会返回给我们这样一个页面,如下图所示: 上面这个页面就是系统自带的页面,你觉得是不是很丑?反正小编本人觉得非常丑,很难 ...

  2. android学习之WebView

    2019独角兽企业重金招聘Python工程师标准>>> WebView是android.webkit包下的一个组件,能用来显示网页. WebView默认是不带地址栏和加进度条的,单单 ...

  3. Android开发之WebView的开发使用(源代码分享)

    如果我们想提供一个web应用程序(或只是一个网页)作为客户端应用程序的一部分,我们可以使用WebView.WebView类是Android的视图类的扩展,它允许您显示web页面的一部分活动布局.担它不 ...

  4. 解决 android 高低版本 webView 里内容 自适应屏幕的终极方法

    解决 android 高低版本 webView 里内容 自适应屏幕的终极方法 参考文章: (1)解决 android 高低版本 webView 里内容 自适应屏幕的终极方法 (2)https://ww ...

  5. Android中脱离WebView使用WebSocket实现群聊和推送功能

    WebSocket是Web2.0时代的新产物,用于弥补HTTP协议的某些不足,不过他们之间真实的关系是兄弟关系,都是对socket的进一步封装,其目前最直观的表现就是服务器推送和聊天功能.更多知识参考 ...

  6. android 代码浏览,Webview实现android简单的浏览器实例代码

    WebView是Android中一个非常实用的组件,它和Safai.Chrome一样都是基于Webkit网页渲染引擎,可以通过加载HTML数据的方式便捷地展现软件的界面,下面通过本文给大家介绍Webv ...

  7. Android中获取WebView加载的html中console.log输出的内容

    场景 Android中使用WebView加载本地html并支持运行JS代码和支持缩放: Android中使用WebView加载本地html并支持运行JS代码和支持缩放_BADAO_LIUMANG_QI ...

  8. Android中的webview详细使用

    webview向html传递参数 方式一  通过 cookie传参 CookieSyncManager.createInstance(this);CookieManager cookieManager ...

  9. Android 8.0学习 (36)---Android 8.0 WebView 拍照、简易预览、二维码扫描 各种问题解决

    Android 8.0 WebView 拍照.简易预览.二维码扫描 各种问题解决 项目用到了WebView包装HTML5做成app使用,其中有页面用到了二维码和拍照上传功能.本人从未做过android ...

最新文章

  1. vue——props的两种常用方法
  2. 使用JAVA建立稳定的多线程服务器
  3. HTML 自学笔记(HTML框架+表单设计)
  4. windows下的正向shell
  5. android数据持久化存储(2)
  6. 【剑指offer】_17正则表达式的匹配
  7. 顺序查找(Sequential Search)
  8. 以前看过一个压缩过的.exe,运行会播放长达半小时的动画,却只有60KB,个人认为其中的原理...
  9. java基础环境搭建_java基础环境搭建
  10. 魔力服务器修改器,魔力宝贝修改器
  11. VSCODE 远程编译调试ARM开发板
  12. Ubuntu 切换谷歌拼音
  13. 淘宝客订单查询API参数说明
  14. Word里表格跨页时自动断开,表格后留有空白部分,未布满整页,如何操作让表格上下页均匀布满?
  15. 大数据项目之电商数仓DataX、DataX简介、DataX支持的数据源、DataX架构原理、DataX部署
  16. 计算机格式化什么意思,格式化硬盘是什么意思?怎么格式?格式了有什么用?会有什么后果?...
  17. 现代人遇到鸿蒙碎片,原来我是盖世奶爸-第126章 虚空之门是鸿蒙鼎碎片?
  18. 杨辉三角(C语言实现)
  19. 服务器硬盘1t等于多少g,1t硬盘实际上等于多少个g?
  20. oracle增加表空间文件

热门文章

  1. 凌晨一点的粤海街道对抗来自美国的力量|湾区人工智能
  2. c语言电子地图程序,C语言 电子地图信息
  3. mimo-ofdm无线通信技术及matlab实现_智芯文库 | FPGA无线通信课程连载——扰码的原理及实现...
  4. iPhone SE 3钢化膜已上架海外市场:4.7英寸屏 Home键得到保留
  5. iPhone13真香了?苹果官网被抢崩了,连夜补货!粉色或成爆款..
  6. 格力电器上半年净利94.57亿元,同比增长48.64%
  7. 三星电子与索尼在CMOS图像传感器市场份额差距缩小
  8. 微信又有大更新!新增多款铃声、腾讯电子签等功能
  9. 有用户反映小米手机充电变慢,官方回应:天气过热
  10. 索尼PS5国行版本周开售 后期将推全配色DualSense手柄