x5开源库后续知识点
目录介绍
- 01.基础使用目录介绍
- 1.0.1 经常使用的基础介绍
- 1.0.2 Android调用Js
- 1.0.3 Js调用Android
- 1.0.4 WebView.loadUrl(url)流程
- 1.0.5 js的调用时机分析
- 1.0.6 清除缓存数据方式有哪些
- 1.0.7 如何使用DeepLink
- 1.0.8 应用被做为第三方浏览器打开
- 02.优化汇总目录介绍
- 2.0.1 视频全屏播放按返回页面被放大
- 2.0.2 加快加载webView中的图片资源
- 2.0.3 自定义加载异常error的状态页面
- 2.0.4 WebView硬件加速致使页面渲染闪烁
- 2.0.5 WebView加载证书错误
- 2.0.6 web音频播放销毁后还有声音
- 2.0.7 DNS采用和客户端API相同的域名
- 2.0.8 如何设置白名单操做
- 2.0.9 后台没法释放js致使发热耗电
- 2.1.0 能够提早显示加载进度条
- 2.1.1 WebView密码明文存储漏洞优化
- 03.问题汇总目录介绍
- 3.0.0 WebView进化史介绍
- 3.0.1 提早初始化WebView必要性
- 3.0.2 x5加载office资源
- 3.0.3 WebView播放视频问题
- 3.0.4 没法获取webView的正确高度
- 3.0.5 使用scheme协议打开连接风险
- 3.0.6 如何处理加载错误
- 3.0.7 webView防止内存泄漏
- 3.0.8 关于js注入时机修改
- 3.0.9 视频/图片宽度超过屏幕
- 3.1.0 如何保证js安全性
- 3.1.1 如何代码开启硬件加速
- 3.1.2 WebView设置Cookie
- 3.1.4 webView加载网页不显示图片
- 3.1.5 绕过证书校验漏洞
- 3.1.6 allowFileAccess漏洞
- 3.1.7 WebView嵌套ScrollView问题
- 3.1.8 WebView中图片点击放大
- 3.1.9 页面滑动期间不渲染/执行
- 3.2.0 被运营商劫持和注入问题
- 3.2.1 解决资源加载缓慢问题
- 3.2.2 判断是否已经滚动到页面底端
- 3.2.3 使用loadData加载html乱码
- 3.2.4 WebView下载进度没法监听
- 3.2.5 webView出现302/303重定向
x5封装库YCWebView开源项目地址
01.基础使用目录介绍
1.0.1 经常使用的基础介绍
- 在activity中最简单的使用
- 那些因素影响页面加载速度
- 影响页面加载速度的因素有很是多,在对 WebView 加载一个网页的过程进行调试发现
- 每次加载的过程当中都会有较多的网络请求,除了 web 页面自身的 URL 请求
- 有 web 页面外部引用的JS、CSS、字体、图片等等都是个独立的http请求。这些请求都是串行的,这些请求加上浏览器的解析、渲染时间就会致使 WebView 总体加载时间变长,消耗的流量也对应的真多。
1.0.2 Android调用Js
- 第一种方式:native 调用 js 的方法,方法为:
- 注意的是名字必定要对应上,要否则是调用不成功的,并且还有一点是 JS 的调用必定要在 onPageFinished 函数回调以后才能调用,要否则也是会失败的。
- 第二种方式:
- 若是如今有需求,咱们要获得一个 Native 调用 Web 的回调怎么办,Google 在 Android4.4 为咱们新增长了一个新方法,这个方法比 loadUrl 方法更加方便简洁,并且比 loadUrl 效率更高,由于 loadUrl 的执行会形成页面刷新一次,这个方法不会,由于这个方法是在 4.4 版本才引入的,因此使用的时候须要添加版本的判断:
- 两种方式的对比
- 通常最常使用的就是第一种方法,可是第一种方法获取返回的值比较麻烦,而第二种方法因为是在 4.4 版本引入的,因此局限性比较大。
- 注意问题
- 记得添加ws.setJavaScriptEnabled(true)代码
1.0.3 Js调用Android
- 第一种方式:经过 addJavascriptInterface 方法进行添加对象映射
- 这种是使用最多的方式了,首先第一步咱们须要设置一个属性:
- 这个函数会有一个警告,由于在特定的版本之下会有很是危险的漏洞,设置完这个属性以后,Native须要定义一个类:
- 在 API17 版本以后,须要在被调用的地方加上 @addJavascriptInterface 约束注解,由于不加上注解的方法是没有办法被调用的
- JS 代码调用
- 这种方式的好处在于使用简单明了,本地和 JS 的约定也很简单,就是对象名称和方法名称约定好便可,缺点就是要提到的漏洞问题。
- 第二种方式:利用 WebViewClient 接口回调方法拦截 url
- 这种方式其实实现也很简单,使用的频次也很高,上面介绍到了 WebViewClient ,其中有个回调接口 shouldOverrideUrlLoading (WebView view, String url)) ,就是利用这个拦截 url,而后解析这个 url 的协议,若是发现是咱们预先约定好的协议就开始解析参数,执行相应的逻辑。注意这个方法在 API24 版本已经废弃了,须要使用 shouldOverrideUrlLoading (WebView view, WebResourceRequest request)) 替代,使用方法很相似,咱们这里就使用 shouldOverrideUrlLoading (WebView view, String url)) 方法来介绍一下:
- 代码很简单,这个方法能够拦截 WebView 中加载 url 的过程,获得对应的 url,咱们就能够经过这个方法,与网页约定好一个协议,若是匹配,执行相应操做。
- 存在问题:这个代码执行以后,就会触发本地的 shouldOverrideUrlLoading 方法,而后进行参数解析,调用指定方法。这个方式不会存在第一种提到的漏洞问题,可是它也有一个很繁琐的地方是,若是 web 端想要获得方法的返回值,只能经过 WebView 的 loadUrl 方法去执行 JS 方法把返回值传递回去,相关的代码以下:
- 第三种方式:利用 WebChromeClient 回调接口的三个方法拦截消息
- 这个方法的原理和第二种方式原理同样,都是拦截相关接口,只是拦截的接口不同:
- 和 WebViewClient 同样,此次添加的是WebChromeClient接口,能够拦截JS中的几个提示方法,也就是几种样式的对话框,在 JS 中有三个经常使用的对话框方法:
- onJsAlert 方法是弹出警告框,通常状况下在 Android 中为 Toast,在文本里面加入\n就能够换行;
- onJsConfirm 弹出确认框,会返回布尔值,经过这个值能够判断点击时确认仍是取消,true表示点击了确认,false表示点击了取消;
- onJsPrompt 弹出输入框,点击确认返回输入框中的值,点击取消返回 null。
- 可是这三种对话框都是能够本地拦截到的,因此能够从这里去作一些更改,拦截这些方法,获得他们的内容,进行解析,好比若是是 JS 的协议,则说明为内部协议,进行下一步解析而后进行相关的操做便可,prompt 方法调用以下所示:
- 须要注意的是 prompt 里面的内容是经过 message 传递过来的,并非第二个参数的 url,返回值是经过 JsPromptResult 对象传递。为何要拦截 onJsPrompt 方法,而不是拦截其余的两个方法,这个从某种意义上来讲都是可行的,可是若是须要返回值给 web 端的话就不行了,由于 onJsAlert 是不能返回值的,而 onJsConfirm 只可以返回肯定或者取消两个值,只有 onJsPrompt 方法是能够返回字符串类型的值,操做最全面方便。
- 以上三种方案的总结和对比
- 以上三种方案都是可行的,在这里总结一下
- 第一种方式:是如今目前最广泛的用法,方便简洁,可是惟一的不足是在 4.2 系统如下存在漏洞问题;
- 第二种方式:经过拦截 url 并解析,若是是已经约定好的协议则进行相应规定好的操做,缺点就是协议的约束须要记录一个规范的文档,并且从 Native 层往 Web 层传递值比较繁琐,优势就是不会存在漏洞,iOS7 之下的版本就是使用的这种方式。
- 第三种方式:和第二种方式的思想实际上是相似的,只是拦截的方法变了,这里拦截了 JS 中的三种对话框方法,而这三种对话框方法的区别就在于返回值问题,alert 对话框没有返回值,confirm 的对话框方法只有两种状态的返回值,prompt 对话框方法能够返回任意类型的返回值,缺点就是协议的制定比较麻烦,须要记录详细的文档,可是不会存在第二种方法的漏洞问题。
1.0.4 WebView.loadUrl(url)流程
- WebView.loadUrl(url)加载网页作了什么?
- 加载网页是一个复杂的过程,在这个过程当中,咱们可能须要执行一些操做,包括:
- 加载网页前,重置WebView状态以及与业务绑定的变量状态。WebView状态包括重定向状态(mTouchByUser)、前端控制的回退栈(mBackStep)等,业务状态包括进度条、当前页的分享内容、分享按钮的显示隐藏等。
- 加载网页前,根据不一样的域拼接本地客户端的参数,包括基本的机型信息、版本信息、登陆信息以及埋点使用的Refer信息等,有时候涉及交易、财产等还须要作额外的配置。
- 开始执行页面加载操做时,会回调WebViewClient.onPageStarted(webview,url,favicon)。在此方法中,能够重置重定向保护的变量(mRedirectProtected),固然也能够在页面加载前重置,因为历史遗留代码问题,此处还没有省去优化。
- 加载页面的过程当中,WebView会回调几个方法。
- 页面加载结束后,WebView会回调几个方法。
- 加载页面的过程当中回调哪些方法?
- WebChromeClient.onReceivedTitle(webview, title),用来设置标题。须要注意的是,在部分Android系统版本中可能会回调屡次这个方法,并且有时候回调的title是一个url,客户端能够针对这种状况进行特殊处理,避免在标题栏显示没必要要的连接。
- WebChromeClient.onProgressChanged(webview, progress),根据这个回调,能够控制进度条的进度(包括显示与隐藏)。通常状况下,想要达到100%的进度须要的时间较长(特别是首次加载),用户长时间等待进度条不消失一定会感到焦虑,影响体验。其实当progress达到80的时候,加载出来的页面已经基本可用了。事实上,国内厂商大部分都会提早隐藏进度条,让用户觉得网页加载很快。
- WebViewClient.shouldInterceptRequest(webview, request),不管是普通的页面请求(使用GET/POST),仍是页面中的异步请求,或者页面中的资源请求,都会回调这个方法,给开发一次拦截请求的机会。在这个方法中,咱们能够进行静态资源的拦截并使用缓存数据代替,也能够拦截页面,使用本身的网络框架来请求数据。包括后面介绍的WebView免流方案,也和此方法有关。
- WebViewClient.shouldOverrideUrlLoading(webview, request),若是遇到了重定向,或者点击了页面中的a标签实现页面跳转,那么会回调这个方法。能够说这个是WebView里面最重要的回调之一,后面WebView与Native页面交互一节将会详细介绍这个方法。
- WebViewClient.onReceivedError(webview,handler,error),加载页面的过程当中发生了错误,会回调这个方法。主要是http错误以及ssl错误。在这两个回调中,咱们能够进行异常上报,监控异常页面、过时页面,及时反馈给运营或前端修改。在处理ssl错误时,遇到不信任的证书能够进行特殊处理,例如对域名进行判断,针对本身公司的域名“放行”,防止进入丑陋的错误证书页面。也能够与Chrome同样,弹出ssl证书疑问弹窗,给用户选择的余地。
- 加载页面结束回调哪些方法
- 会回调WebViewClient.onPageFinished(webview,url)。
- 这时候能够根据回退栈的状况判断是否显示关闭WebView按钮。经过mActivityWeb.canGoBackOrForward(-1)判断是否能够回退。
1.0.5 js的调用时机分析
- onPageFinished()或者onPageStarted()方法中注入js代码
- 作过WebView开发,而且须要和js交互,大部分都会认为js在WebViewClient.onPageFinished()方法中注入最合适,此时dom树已经构建完成,页面已经彻底展示出来。但若是作过页面加载速度的测试,会发现WebViewClient.onPageFinished()方法一般须要等待好久才会回调(首次加载一般超过3s),这是由于WebView须要加载完一个网页里主文档和全部的资源才会回调这个方法。
- 能不能在WebViewClient.onPageStarted()中注入呢?答案是不肯定。通过测试,有些机型能够,有些机型不行。在WebViewClient.onPageStarted()中注入还有一个致命的问题——这个方法可能会回调屡次,会形成js代码的屡次注入。
- 从7.0开始,WebView加载js方式发生了一些小改变,官方建议把js注入的时机放在页面开始加载以后。
- WebViewClient.onProgressChanged()方法中注入js代码
- WebViewClient.onProgressChanged()这个方法在dom树渲染的过程当中会回调屡次,每次都会告诉咱们当前加载的进度。
- 在这个方法中,能够给WebView自定义进度条,相似微信加载网页时的那种进度条
- 若是在此方法中注入js代码,则须要避免重复注入,须要加强逻辑。能够定义一个boolean值变量控制注入时机
- 那么有人会问,加载到多少才须要处理js注入逻辑呢?
- 正是由于这个缘由,页面的进度加载到80%的时候,实际上dom树已经渲染得差很少了,代表WebView已经解析了标签,这时候注入必定是成功的。在WebViewClient.onProgressChanged()实现js注入有几个须要注意的地方:
- 1 上文提到的屡次注入控制,使用了boolean值变量控制
- 2 从新加载一个URL以前,须要重置boolean值变量,让从新加载后的页面再次注入js
- 3 若是作过本地js,css等缓存,则先判断本地是否存在,若存在则加载本地,不然加载网络js
- 4 注入的进度阈值能够自由定制,理论上10%-100%都是合理的,不过建议使用了75%到90%之间能够。
1.0.6 清除缓存数据方式有哪些
1.0.7 如何使用DeepLink
1.0.8 应用被做为第三方浏览器打开
- 微信里的文章页面,能够选择“在浏览器打开”。如今不少应用都内嵌了WebView,那是否可使本身的应用做为第三方浏览器打开此文章呢?
- 在Manifest文件中,给想要接收跳转的Activity添加<intent-filter>配置:
- 而后在 X5WebViewActivity 中获取相关传递数据。具体能够看lib中的X5WebViewActivity类代码。
- 一些重点说明
- 在微信中“经过浏览器”打开本身的应用,而后将本身的应用切到后台。重复上面的操做,会一直建立应用的实例,这样确定是很差的,为了不这种状况咱们设置启动模式为:launchMode="singleTask"。
02.优化汇总目录介绍
2.0.1 视频全屏播放按返回页面被放大(部分手机出现)
2.0.2 加载webView中的资源时,加快加载的速度优化,主要是针对图片
- html代码下载到WebView后,webkit开始解析网页各个节点,发现有外部样式文件或者外部脚本文件时,会异步发起网络请求下载文件,但若是在这以前也有解析到image节点,那势必也会发起网络请求下载相应的图片。在网络状况较差的状况下,过多的网络请求就会形成带宽紧张,影响到css或js文件加载完成的时间,形成页面空白loading太久。解决的方法就是告诉WebView先不要自动加载图片,等页面finish后再发起图片加载。
2.0.3 自定义加载异常error的状态页面,好比下面这些方法中可能会出现error
- 当WebView加载页面出错时(通常为404 NOT FOUND),安卓WebView会默认显示一个出错界面。当WebView加载出错时,会在WebViewClient实例中的onReceivedError(),还有onReceivedTitle方法接收到错误
2.0.4 WebView硬件加速致使页面渲染闪烁
- 4.0以上的系统咱们开启硬件加速后,WebView渲染页面更加快速,拖动也更加顺滑。但有个反作用就是,当WebView视图被总体遮住一块,而后忽然恢复时(好比使用SlideMenu将WebView从侧边滑出来时),这个过渡期会出现白块同时界面闪烁。解决这个问题的方法是在过渡期前将WebView的硬件加速临时关闭,过渡期后再开启
2.0.5 WebView加载证书错误
- webView加载一些别人的url时候,有时候会发生证书认证错误的状况,这时候咱们但愿可以正常的呈现页面给用户,咱们须要忽略证书错误,须要调用WebViewClient类的onReceivedSslError方法,调用handler.proceed()来忽略该证书错误。
2.0.6 web音频播放销毁后还有声音
- WebView页面中播放了音频,退出Activity后音频仍然在播放,须要在Activity的onDestory()中调用
2.0.7 DNS采用和客户端API相同的域名
- 创建链接/服务器处理;在页面请求的数据返回以前,主要有如下过程耗费时间。
- DNS采用和客户端API相同的域名
2.0.8 如何设置白名单操做
- 客户端内的WebView都是能够经过客户端的某个schema打开的,而要打开页面的URL不少都并不写在客户端内,而是能够由URL中的参数传递过去的。上面4.0.5 使用scheme协议打开连接风险已经说明了scheme使用的危险性,那么如何避免这个问题了,设置运行访问的白名单。或者当用户打开外部连接前给用户强烈而明显的提示。具体操做以下所示:
- 在onPageStarted开始加载资源的方法中,获取加载url的host值,而后和本地保存的合法host作比较,这里domainList是一个数组
- 设置白名单操做其实和过滤广告是一个意思,这里你能够放一些合法的网址容许访问。
2.0.9 后台没法释放js致使发热耗电
- 在有些手机你若是webView加载的html里,有一些js一直在执行好比动画之类的东西,若是此刻webView 挂在了后台这些资源是不会被释放用户也没法感知。
- 致使一直占有cpu 耗电特别快,因此若是遇到这种状况,处理方式以下所示。大概意思就是在后台的时候,会调用onStop方法,即此时关闭js交互,回到前台调用onResume再开启js交互。
2.1.0 能够提早显示加载进度条
- 提早显示进度条不是提高性能 , 可是对用户体验来讲也是很重要的一点 , WebView.loadUrl("url") 不会立马就回调 onPageStarted 或者 onProgressChanged 由于在这一时间段,WebView 有可能在初始化内核,也有可能在与服务器创建链接,这个时间段容易出现白屏,白屏用户体验是很糟糕的 ,因此建议
2.1.1 WebView密码明文存储漏洞优化
- WebView 默认开启密码保存功能 mWebView.setSavePassword(true),若是该功能未关闭,在用户输入密码时,会弹出提示框,询问用户是否保存密码,若是选择”是”,密码会被明文保到 /data/data/com.package.name/databases/webview.db 中,这样就有被盗取密码的危险,因此须要经过 WebSettings.setSavePassword(false) 关闭密码保存提醒功能。
03.问题汇总目录介绍
3.0.0 WebView进化史介绍
- 进化史以下所示
- 从Android4.4系统开始,Chromium内核取代了Webkit内核。
- 从Android5.0系统开始,WebView移植成了一个独立的apk,能够不依赖系统而独立存在和更新。
- 从Android7.0 系统开始,若是用户手机里安装了 Chrome , 系统优先选择 Chrome 为应用提供 WebView 渲染。
- 从Android8.0系统开始,默认开启WebView多进程模式,即WebView运行在独立的沙盒进程中。
3.0.1 提早初始化WebView必要性
- 第一次打开Web面 ,使用WebView加载页面的时候特别慢,第二次打开就能明显的感受到速度有提高,为何?
- 是由于在你第一次加载页面的时候 WebView 内核并无初始化 ,因此在第一次加载页面的时候须要耗时去初始化WebView内核 。
- 提早初始化WebView内核 ,例如以下把它放到了Application里面去初始化 , 在页面里能够直接使用该WebView,这种方法能够比较有效的减小WebView在App中的首次打开时间。当用户访问页面时,不须要初始化WebView的时间。
- 可是这样也有很差的地方,额外的内存消耗。页面间跳转须要清空上一个页面的痕迹,更容易内存泄露。
3.0.2 x5加载office资源
- 关于加载word,pdf,xls等文档文件注意事项:Tbs不支持加载网络的文件,须要先把文件下载到本地,而后再加载出来
- 还有一点要注意,在onDestroy方法中调用此方法mTbsReaderView.onStop(),不然第二次打开没法浏览。更多能够看FileReaderView类代码!
3.0.3 WebView播放视频问题
- 一、这次的方案用到WebView,并且其中会有视频嵌套,在默认的WebView中直接播放视频会有问题, 并且不一样的SDK版本状况还不同,网上搜索了下解决方案,在此记录下. webView.getSettings.setPluginState(PluginState.ON);webView.setWebChromeClient(new WebChromeClient());
- 二、而后在webView的Activity配置里面加上: android:hardwareAccelerated="true"
- 三、以上能够正常播放视频了,可是webview的页面都finish了竟然还能听 到视频播放的声音, 因而又查了下发现webview的onResume方法能够继续播放,onPause能够暂停播放, 可是这两个方法都是在Added in API level 11添加的,因此须要用反射来完成。
- 四、中止播放:在页面的onPause方法中使用:webView.getClass().getMethod("onPause").invoke(webView, (Object[])null);
- 五、继续播放:在页面的onResume方法中使用:webView.getClass().getMethod("onResume").invoke(webView,(Object[])null);这样就能够控制视频的暂停和继续播放了。
3.0.4 没法获取webView的正确高度
- 偶发状况,获取不到webView的内容高度
- 其中htmlString是一个HTML格式的字符串。
- 这是由于onPageFinished回调指的WebView已经完成从网络读取的字节数,这一点。在点onPageFinished被激发的页面可能尚未被解析。
- 第一种解决办法:提供onPageFinished()一些延迟
- 第二种解决办法:使用js获取内容高度,具体能够看这篇文章:https://www.jianshu.com/p/ad22b2649fba
3.0.5 使用scheme协议打开连接风险
- 常见的用法是在APP获取到来自网页的数据后,从新生成一个intent,而后发送给别的组件使用这些数据。好比使用Webview相关的Activity来加载一个来自网页的url,若是此url来自url scheme中的参数,如:yc://ycbjie:8888/from?load_url=http://www.taobao.com。
- 若是在APP中,没有检查获取到的load_url的值,攻击者能够构造钓鱼网站,诱导用户点击加载,就能够盗取用户信息。
- 这个时候,别人非法篡改参数,因而将scheme协议改为yc://ycbjie:8888/from?load_url=http://www.doubi.com。这个时候点击进去便可进入钓鱼连接地址。
- 使用建议
- APP中任何接收外部输入数据的地方都是潜在的攻击点,过滤检查来自网页的参数。
- 不要经过网页传输敏感信息,有的网站为了引导已经登陆的用户到APP上使用,会使用脚本动态的生成URL Scheme的参数,其中包括了用户名、密码或者登陆态token等敏感信息,让用户打开APP直接就登陆了。恶意应用也能够注册相同的URL Sechme来截取这些敏感信息。Android系统会让用户选择使用哪一个应用打开连接,可是若是用户不注意,就会使用恶意应用打开,致使敏感信息泄露或者其余风险。
- 解决办法
- 在内嵌的WebView中应该限制容许打开的WebView的域名,并设置运行访问的白名单。或者当用户打开外部连接前给用户强烈而明显的提示。具体操做能够看5.0.8 如何设置白名单操做方式。
3.0.6 如何处理加载错误(Http、SSL、Resource)
- 对于WebView加载一个网页过程当中所产生的错误回调,大体有三种
3.0.7 webView防止内存泄漏
3.0.9 视频/图片宽度超过屏幕
- 视频播放宽度或者图片宽度比webView设置的宽度大,超过屏幕:这个时候能够设置ws.setLoadWithOverviewMode(false);
- 另一种让图片不超出屏幕范围的方法,能够用的是css
- 经过webView的setting属性设置
3.1.0 如何保证js安全性
- Android和js如何通讯
- 为了与Web页面实现动态交互,Android应用程序容许WebView经过WebView.addJavascriptInterface接口向Web页面注入Java对象,页面Javascript脚本可直接引用该对象并调用该对象的方法。
- 这类应用程序通常都会有相似以下的代码:
- 此段代码将javaObj对象暴露给js脚本,能够经过jsObj对象对其进行引用,调用javaObj的方法。结合Java的反射机制能够经过js脚本执行任意Java代码,相关代码以下:
- 当受影响的应用程序执行到上述脚本的时候,就会执行someCmd指定的命令。
- addJavascriptInterface任何命令执行漏洞
- 在webView中使用js与html进行交互是一个不错的方式,可是,在Android4.2(16,包含4.2)及如下版本中,若是使用addJavascriptInterface,则会存在被注入js接口的漏洞;在4.2以后,因为Google增长了@JavascriptInterface,该漏洞得以解决。
- @JavascriptInterface注解作了什么操做
- 以前,任何Public的函数均可以在JS代码中访问,而Java对象继承关系会致使不少Public的函数均可以在JS中访问,其中一个重要的函数就是getClass()。而后JS能够经过反射来访问其余一些内容。经过引入 @JavascriptInterface注解,则在JS中只能访问 @JavascriptInterface注解的函数。这样就能够加强安全性。
3.1.1 如何代码开启硬件加速
- 开启软硬件加速这个性能提高仍是很明显的,可是会耗费更大的内存 。直接调用代码api便可完成,webView.setOpenLayerType(true);
3.1.2 WebView设置Cookie
- h5页面为什么要设置cookie,主要是避免网页重复登陆,做用是记录用户登陆信息,下次进去不须要重复登陆。
- 代码里怎么设置Cookie,以下所示
- 在android里面在调用webView.loadUrl(url)以前一句调用此方法就能够给WebView设置Cookie
- 注:这里必定要注意一点,在调用设置Cookie以后不能再设置,不然设置Cookie无效。该处须要校验,为什么???
- 还有跨域问题: 域A: test1.yc.com 域B: test2.yc.com
- Cookie的过时机制
- 能够设置Cookie的生效时间字段名为: expires 或 max-age。
- expires:过时的时间点
- max-age:生效的持续时间,单位为秒。
- 若将Cookie的 max-age 设置为负数,或者 expires 字段设置为过时时间点,数据库更新后这条Cookie将从数据库中被删除。若是将Cookie的 max-age 和 expires 字段设置为正常的过时日期,则到期后再数据库更新时会删除该条数据。
- 下面列出几个有用的接口:
- 获取某个url下的全部Cookie:CookieManager.getInstance().getCookie(url)
- 判断WebView是否接受Cookie:CookieManager.getInstance().acceptCookie()
- 清除Session Cookie:CookieManager.getInstance().removeSessionCookies(ValueCallback<Boolean> callback)
- 清除全部Cookie:CookieManager.getInstance().removeAllCookies(ValueCallback<Boolean> callback)
- Cookie持久化:CookieManager.getInstance().flush()
- 针对某个主机设置Cookie:CookieManager.getInstance().setCookie(String url, String value)
3.1.4 webView加载网页不显示图片
- webView从Lollipop(5.0)开始webView默认不容许混合模式, https当中不能加载http资源, 而开发的时候可能使用的是https的连接, 可是连接中的图片多是http的, 因此须要设置开启。
3.1.5 绕过证书校验漏洞
- webviewClient中有onReceivedError方法,当出现证书校验错误时,咱们能够在该方法中使用handler.proceed()来忽略证书校验继续加载网页,或者使用默认的handler.cancel()来终端加载。
- 由于咱们使用了handler.proceed(),由此产生了该“绕过证书校验漏洞”。若是肯定全部页面都能知足证书校验,则没必要要使用handler.proceed()
3.1.6 allowFileAccess漏洞
- 若是webView.getSettings().setAllowFileAccess(boolean)设置为true,则会面临该问题;该漏洞是经过WebView对Javascript的延时执行和html文件替换产生的。
- 解决方案是禁止WebView页面打开本地文件,即:webView.getSettings().setAllowFileAccess(false);
- 或者更直接的禁止使用JavaScript:webView.getSettings().setJavaScriptEnabled(false);
- 问题描述
- 当 WebView 嵌套在 ScrollView 里面的时候,若是 WebView 先加载了一个高度很高的网页,而后加载了一个高度很低的网页,就会形成 WebView 的高度没法自适应,底部出现大量空白的状况出现。
- 解决办法
3.1.8 WebView中图片点击放大
- 首先载入js
- html加载完成以后,添加监听图片的点击js函数,这个能够在onPageFinished方法中操做
- 具体看addImageArrayClickListener的实现方法。
- 最后看看js的通讯接口作了什么
3.1.9 页面滑动期间不渲染/执行
- 在有些需求中会有一些吸顶的元素,例如导航条,购买按钮等;当页面滚动超出元素高度后,元素吸附在屏幕顶部。在WebView中成了难题:在页面滚动期间,Scroll Event不触发。不只如此,WebView在滚动期间还有各类限定:
- setTimeout和setInterval不触发。
- GIF动画不播放。
- 不少回调会延迟到页面中止滚动以后。
- background-position: fixed不支持。
- 这些限制让WebView在滚动期间很难有较好的体验。这些限制大部分是不可突破的,但至少对于吸顶功能仍是能够作一些支持,解决方法:
- 在Android上,监听touchMove事件能够在滑动期间作元素的position切换(惯性运动期间就无效了)。
- 参考美团技术文章
3.2.0 被运营商劫持和注入问题
- 因为WebView加载的页面代码是从服务器动态获取的,这些代码将会很容易被中间环节所窃取或者修改,其中最主要的问题出自地方运营商和一些WiFi。监测到的问题包括:
- 无视通讯规则强制缓存页面。
- header被篡改。
- 页面被注入广告。
- 页面被重定向。
- 页面被重定向并从新iframe到新页面,框架嵌入广告。
- HTTPS请求被拦截。
- DNS劫持。
- 针对页面注入的行为,有一些解决方案:
- 1.使用CSP(Content Security Policy)
- 2.HTTPS。
- HTTPS能够防止页面被劫持或者注入,然而其反作用也是明显的,网络传输的性能和成功率都会降低,并且HTTPS的页面会要求页面内全部引用的资源也是HTTPS的,对于大型网站其迁移成本并不算低。HTTPS的一个问题在于:一旦底层想要篡改或者劫持,会致使整个连接失效,页面没法展现。这会带来一个问题:原本页面只是会被注入广告,并且广告会被CSP拦截,而采用了HTTPS后,整个网页因为受到劫持彻底没法展现。
- 对于安全要求不高的静态页面,就须要权衡HTTPS带来的利与弊了。
- 3.App使用Socket代理请求
- 若是HTTP请求容易被拦截,那么让App将其转换为一个Socket请求,并代理WebView的访问也是一个办法。
- 一般不法运营商或者WiFi都只能拦截HTTP(S)请求,对于自定义的包内容则没法拦截,所以能够基本解决注入和劫持的问题。
- Socket代理请求也存在问题:
- 首先,使用客户端代理的页面HTML请求将丧失边下载边解析的能力;根据前面所述,浏览器在HTML收到部份内容后就马上开始解析,并加载解析出来的外链、图片等,执行内联的脚本……而目前WebView对外并无暴露这种流式的HTML接口,只能由客户端彻底下载好HTML后,注入到WebView中。所以其性能将会受到影响。
- 其次,其技术问题也是较多的,例如对跳转的处理,对缓存的处理,对CDN的处理等等……稍不留神就会埋下若干大坑。
- 此外还有一些其余的办法,例如页面的MD5检测,页面静态页打包下载等等方式,具体如何选择还要根据具体的场景抉择。
3.2.1 解决资源加载缓慢问题
- 在资源预加载方面,其实也有不少种方式,下面主要列举了一些:
- 第一种方式是使用 WebView 自身的缓存机制:若是咱们在 APP 里面访问一个页面,短期内再次访问这个页面的时候,就会感受到第二次打开的时候顺畅不少,加载速度比第一次的时间要短,这个就是由于 WebView 自身内部会作一些缓存,只要打开过的资源,他都会试着缓存到本地,第二次须要访问的时候他直接从本地读取,可是这个读取实际上是不太稳定的东西,关掉以后,或者说这种缓存失效以后,系统会自动把它清除,咱们没办法进行控制。基于这个 WebView 自身的缓存,有一种资源预加载的方案就是,咱们在应用启动的时候能够开一个像素的 WebView ,事先去访问一下咱们经常使用的资源,后续打开页面的时候若是再用到这些资源他就能够从本地获取到,页面加载的时间会短一些。
- 第二种方案是,本身去构建和管理缓存:把这些须要预加载的资源放在 APP 里面,多是预先放进去的,也多是后续下载的,问题在于前端这些页面怎么去缓存,两个方案,第一种是前端能够在 H5 打包的时候把里面的资源 URL 进行替换,这样能够直接访问本地的地址;第二种是客户端能够拦截这些网页发出的全部请求作替换。
- 具体能够看美团的技术文章:美团大众点评 Hybrid 化建设
3.2.2 判断是否已经滚动到页面底端
- getScrollY()方法返回的是当前可见区域的顶端距整个页面顶端的距离,也就是当前内容滚动的距离.
- getHeight()或者getBottom()方法都返回当前WebView 这个容器的高度
- getContentHeight 返回的是整个html的高度,但并不等同于当前整个页面的高度,由于WebView有缩放功能,因此当前整个页面的高度实际上应该是原始html 的高度再乘上缩放比例. 所以,更正后的结果,准确的判断方法应该是:
3.2.3 使用loadData加载html乱码
- 能够经过使用 WebView.loadData(String data, String mimeType, String encoding)) 方法来加载一整个 HTML 页面的一小段内容,第一个就是咱们须要 WebView 展现的内容,第二个是咱们告诉 WebView 咱们展现内容的类型,通常,第三个是字节码,可是使用的时候,这里会有一些坑
- 明明已经指定了编码格式为 UTF-8,加载却还会出现乱码……
- 使用loadData()或 loadDataWithBaseURL()加载一段HTML代码片断
- data:是要加载的数据类型,但在数据里面不能出现英文字符:'#', '%', '' , '?' 这四个字符,若是有的话能够用 %23, %25, %27, %3f,这些字符来替换,在平时测试时,你的数据时,你的数据里含有这些字符,但不会出问题,当出问题时,你能够替换下。
- %,会报找不到页面错误,页面全是乱码。乱码样式见符件。
- #,会让你的goBack失效,但canGoBAck是可使用的。因而就会产生返回按钮生效,但不能返回的状况。
- \ 和? 我在转换时,会报错,由于它会把\看成转义符来使用,若是用两级转义,也不生效,我是对它无语了。
- 咱们在使用loadData时,就意味着须要把全部的非法字符所有转换掉,这样就会给运行速度带来很大的影响,由于在使用时,在页面stytle中会使用不少%号。页面的数据越多,运行的速度就会越慢。
- data中,有人会遇到中文乱码问题,解决办法:参数传"utf-8",页面的编码格式也必须是utf-8,这样编码统一就不会乱了。别的编码我也没有试过。
- 解决办法
3.2.4 WebView下载进度没法监听
3.2.5 webView出现302/303重定向
- 专业叙述
- 网络解释
- 重定向是网页制做中的一个知识,几个例子跟你说明,假设你如今所处的位置是一个论坛的登陆页面,你填写了账号,密码,点击登录,若是你的账号密码正确,就自动跳转到论坛的首页,不正确就返回登陆页;这里的自动跳转,就是重定向的意思。或者能够说,重定向就是,在网页上设置一个约束条件,条件知足,就自动转入到其它网页、网址 。好比,你输入一个网站连接,通常能够直接进入网站,若是出现错误,则又跳转到另一个网页。
- 举个例子
- 叙述下这种问题的状况,就是WebView首先加载A连接,而后在WebView上点击一个B连接进行加载,B连接会自动跳转到C连接,这个时候调用WebView的goback方法,会返回到加载B连接,可是B连接又会跳转到C连接,从而致使无法返回到A连接界面(固然也有朋友说快速的按两次返回键-也就是连续触发了两次goback能够返回到A连接,但并非全部用户都懂这个,并且操做上也很恶心。),这就是重定向问题。
- 实现WebView的滑动监听和优雅处理回退栈问题
- WebView可否知道某个url是否是301/302呢?固然知道,WebView可以拿到url的请求信息和响应信息,根据header里的code很轻松就能够实现,事实正是如此,交给WebView来处理重定向(return false),这时候按返回键,是能够正常地回到重定向以前的那个页面的。(PS:从上面的章节可知,WebView在5.0之后是一个独立的apk,能够单独升级,新版本的WebView实现确定处理了重定向问题)
- 可是,业务对url拦截有需求,确定不能把全部的状况都交给系统WebView处理。为了解决url拦截问题,本文引入了另外一种思想——经过用户的touch事件来判断重定向。具体能够看项目lib中的ScrollWebView!
04.关于参考
05.关于x5开源库YCWebView
5.0.1 前沿说明
- 基于腾讯x5封源库,提升webView开发效率,大概要节约你百分之六十的时间成本。该案例支持处理js的交互逻辑且无耦合、同时暴露进度条加载进度、能够监听异常error状态、支持视频播放而且能够全频、支持加载word,xls,ppt,pdf,txt等文件文档、发短信、打电话、发邮件、打开文件操做上传图片、唤起原生App、x5库为最新版本,功能强大。
5.0.2 该库功能和优点
- 提升webView开发效率,大概要节约你百分之六十的时间成本,一键初始化操做;
- 支持处理js的交互逻辑,方便快捷,而且无耦合,操做十分简单;
- 暴露进度条加载进度,结束,以及异常状态(分多种状态:无网络,404,onReceivedError,sslError异常等)listener给开发者;
- 支持视频播放,能够切换成全频播放视频,可旋转屏幕,暴露视频操做监听listener给开发者;
- 集成了腾讯x5的WebView,最新版本,功能强大;
- 支持打开文件的操做,好比打开相册,而后选中图片上传,兼容版本(5.0);
- 支持加载word,xls,ppt,pdf,txt等文件文档,使用方法十分简单;
- 支持设置仿微信加载H5页面进度条,彻底无耦合,操做简单,极大提升用户体验;
5.0.3 项目地址
欢迎关注本站公众号,获取更多信息