Android 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-ModiedETag控制不完全,依然无法很好的避免过渡请求网页资源,因此,需要一套可控的缓存策略,来突破缓存容量过小和图片缓存策略统一的问题。

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

    资源本地化.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
  • 本地资源拦截替换
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容