webview问题

目录

  • 引言:Html加载流程
  • 加载流程各节点耗时分析优化
  • 加载流程结构优化
  • 客户端优化

Html加载流程

  1. 创建并初始化WebView
  2. 下载网页所需资源文件
  3. 渲染展示网页

 

HTML加载流程.png

加载流程各节点耗时分析优化

  • WebView创建初始化
    首次初始化WebView会比第二次初始化慢很多。初始化后,即使WebView已释放,但一些多WebView共用的全局服务/资源对想仍未释放,而第二次初始化不需要生成,因此初始化变快。
  • 1. 提前初始化, 提前预备全局WebView,Application中初始化WebView备用
  •  
  •  @Override
  •  public void onCreate() {
  •       // Application中提前初始化WebView
  •       WebView mWebView = new WebView(new MutableContextWrapper(this))
  •  }

注:该方式会增加冷启动时间

2. WebView复用,维护WebView pool,避免每次打开网页创建WebView。

例如:VasSonic方案

  • DNS解析耗时
    html网页文件获取过程中,首先需要将url链接解析成ip地址,根据ip地址获取到对应html文件。
  • 1. DNS会在系统级别进行缓存,对于WebView的地址,如果使用的域名与原生api的相同,则可直接使用缓存,避免DNS解析耗时。
  • 资源文件下载耗时
    弱网情况下,下载网页资源耗时,导致白屏时间过长。
  • 1. 网页资源压缩,并CDN加速处理,缩短请求耗时。
  • 2. 服务端下发填充好首屏数据的网页,作为网页首屏展示,减少网页上数据请求时间。
  • 3. App闲置状态时,下载离线包到本地,加载时优先加载离线包数据。后续更新接收下发的差异包,与当前离线包合并成完整包。
  • HTML解析耗时
    解析html文件,构建DOM树,耗时取决于html节点嵌套复杂程度,与硬件解析能力强弱。
  • css文件加载解析、js加载
    一般来说Html在开始接收到数据返回数据时就开始解析并构建DOM树,如果没有JS阻塞的话一般会相继完成,通常情况下,下面代码的link部分和script部分如果单独出现,都不会阻塞页面的解析,但,当两部分同时出现时,css加载会阻塞下面的内联JS的执行,从而阻塞阻塞Html文件的解析。
  • 1. 为防止JS阻塞Html的解析,Web端需延迟JS解析。
  • 绘制渲染
    布局绘制是一个递归过程,从呈现根节点开始,递归遍历子节点,计算几何集合信息。因此,html标签越复杂、嵌套越深,则布局耗时越久。
  • 1. 优化网页布局,减少布局层次。

加载流程结构优化

  • 流程优化
    默认状态下,WebView初始化与资源文件下载为线性同步执行,此时WebView初始化时,网络为空闲状态,并行处理WebView初始化与资源文件下载可缩短网页显示的总耗时。

第一阶段为:创建初始化WebView(Launch WebView)
第二阶段为:请求网页资源(Native(Sonic) Request)

 

串行模式.png

 

 

并行模式.png


但,由于WebView初始化与请求网页资源操作结束时间先后无可得知。

方案:流式拦截,加入中间层来桥接内核和数据

  1. 启动子线程请求页面主资源,子线程中不断将网络数据读取到内存中。
  2. WebView初始化完成的时候,提供中间层BridgeStream来连接WebView和数据流;
  3. WebView读取数据时,中间层BridgeStream先把内存的数据读取返回后,再继续读取网络的数据。

 

中间件.png

 

通过桥接流的方式,整个内核无需等待,边加载边解析

客户端优化

  • 合理使用WebView提供的几种缓存方式
    1. 浏览器缓存。内置自动实现
    2. Application Cache 缓存

webSettings.setAppCacheEnabled(true)
webSettings.setAppCacheMaxSize(yourCacheSize)
webSettings.setAppCachePath(yourCacheDirPath)

    1. DOM Storage 缓存

setDomStorageEnabled(true)

    1. Web SQL Database 缓存

webSettings.setDatabaseEnabled(true)
webSettings.setDatabasePath(yourCacheDirPath)

    1. Indexed Database 缓存。Android 4.4以上支持

webSettings.setJavaScriptEnabled(true)

如何缓存html、js、css、图片等文件,通过缓存机制,对于应用提高资源文件的加载速度、流量优化有很大意义。而具体该针对哪种资源使用哪个缓存字段,以及缓存时长设置就比较重要。若时长设置的太短,则缓存效果受影响,若时长设置过长,则不能及时获取服务器最新数据。

  • html、js、css资源
    考虑到这些文件会随着业务需求经常变化。为此,这些文件可以使用Last-Modified(Etag)来控制缓存
  • 图片、音视频资源
    图片也可以通过Last-Modified(Etag)来控制缓存。但这样每次都需向服务器发起查询请求,考虑到图片文件长时间变动不大,推荐使用Cache-Control设置一个较长的时间来缓存。
  • 除此之外,也可以使用Application Cache机制,由前端控制缓存文件,客户端设置缓存路径和大小。

由于,WebView各缓存机制的缓存大小有限,时常导致最开始的缓存被清理;浏览器缓存Last-Modied和ETag控制不完全,依然无法很好的避免过渡请求网页资源,因此,需要一套可控的缓存策略,来突破缓存容量过小和图片缓存策略统一的问题。

  • 资源本地化
    网页加载到显示,需要下载大量文件,其中不乏有些体积大并且基本固定不动的资源,此时,可把这些资源预置在项目中,加载时从本地加载,方案与离线包方案类似。

 

资源本地化.png

大致操作如下:

    1. 方式一、JS方法注入

   // 1. 固定资源放到项目文件夹,如/Assets文件夹中

   // 2. 注入JS方法

   webView.addJavascriptInterface(new JsInterface(), "JsInterface")

   private class JsInterface {

      @JavascriptInterface

      public String getLocalSrc(String src) {

           return "file://storage/emulated/0/app/file/a.jpeg"

      }

   }

   // 3. 页面加载完成时,修改图片标签

   private class MyWebViewClient extends WebViewClient {

 

    @Override

    public void onPageFinished(WebView view, String url) {

        super.onPageFinished(view, url);

        String js = "javascript:(function() {

             var objs = document.getElementsByTagName('img');

             for (var i = 0; i < objs.length; i++)  {

                  var imgUrl = objs[i].getAttribute('src');

                  var localUrl = window.local_obj.getLocalSrc(imgUrl);

                  if (localUrl) {

                      objs[i].setAttribute('src', localUrl);

                  }

             }

        })()"

 

        view.loadUrl(js);

    }

}

  1. 方式二、请求拦截

  webView.setWebViewClient(new WebViewClient() {

      // 为方便,此处进写Api 21以下方法,Api21 以上雷同

      @Override

      public WebResourceResponse shouldInterceptRequest(WebView view, String url) {

           // 1. 判断拦截资源的条件

           if (url.contains("logo.gif")) {

                // 假设网页图片资源为:http://abc.com/image/logo.gif

                // 图片资源文件名为:logo.gif

 

                // 2. 创建输入流

                InputStream is = null

 

                try {

                    // 3. 获得需要替换的资源(存放在assets文件夹中)

                    is = getApplicationContext().getAssets().open("image/abc.png")

                } catch (IOException e) {

                    e.printStackTrace()

                }

 

                // 4. 替换资源

                WebResourceResponse reponse = new WebResourceResponse("image/png", "utf-8", is)

                return response

           }

           return super.shouldInterceptRequest(view, url)

      }

  })

此外,客户端需要预置资源,并维护网络图片url和本地图片自检的关联,根据一定策略保证本地预置资源为最新资源。若预置资源不限于图片资源,由于html、js、css等资源容易发生变化,因此还需实现一套机制实现本地资源和服务端数据及时的更新。即服务端需要支持版本控制和资源增量下发等功能。

总结

结合手Q、网易严选、美团等其他方面优化方案,大致如下:

  • WebView在Application中提前初始化
  • 实现WebView复用
  • 另开WebView进程
  • DNS解析优化(接口与网页主域名一致)
  • 线上资源压缩、CDN加速
  • 静态直出,直接下发首屏html
  • 离线预推,下发离线包,并增量更新
  • WebView创建与网络请求并行
  • 网页按节点局部刷新
  • 自定义实现图片资源缓存
  • 重新定义图片加载格式,shareP
  • 本地资源拦截替换



 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值