加载webview内核
- 设置缓存
- webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
- webSettings.setDatabaseEnabled(true);
- webSettings.setDomStorageEnabled(true);
- webSettings.setAppCacheEnabled(true);
- 在Android 4.2到Android N之间,系统为了组件切换的流程性考虑,setDrawDuringWindowsAnimating为false,反射成true
- android n以上 & android 4.1以下不存在此问题,无须处理
- 4.2不存在setDrawDuringWindowsAnimating,需要特殊处理。可以反射handleDispatchDoneAnimating来解决
- 4.3及以上,反射setDrawDuringWindowsAnimating来实现动画过程中渲染
- Chrome Custom Tabs
- 允许 App 直接调用 Chrome 渲染网页
- 需要用户有安装 chrome,并且被设置为默认浏览器;系统的要求是 4.3(API 18)以上,Chrome 版本 45+
- 可以在 APP 启动时预先初始化一个 webview 然后释放,这样等用户真正走到 H5 模块去加载 webview时就变快了。
- 全局WebView(约10M左右的内存占用)
- 在客户端刚启动时,就初始化一个全局的WebView待用,并隐藏;当用户访问了WebView时,直接使用这个WebView加载对应网页,并展示。
- 页面间跳转需要清空上一个页面的痕迹,更容易内存泄露,在 APP 运行期间都无法释放。
- 客户端代理数据请求
- 在客户端初始化WebView的同时,直接由native开始网络请求数据;当页面初始化完成后,向native获取其代理请求的数据。
- Webview在Android 4.0上已经默认开启硬件加速,硬件加速如果导致页面渲染问题,可以关闭硬件加速。
- 内核渲染优化
- 三个线程(IOThread、MainThread、ParserThread)
- IOThread会从网络端或者本地获取html数据,并把数据交给MainThread(渲染线程,十分繁忙,用于JS执行,页面布局等),为了保证MainThread不被阻塞,需要额外起一个后台线程(ParserThread)用来做html的解析工作。ParserThread每解析到落地页html中带有特殊class标记的一个div标签或者P标签(图中的first、second)时,就会触发一次MainThread的layout工作,并把layout后得到的高度与屏幕高度进行对比,如果当前layout高度已经大于屏幕高度,认为首屏内容已经完成布局,可以触发渲染上屏逻辑
建立连接/服务器处理
- DNS采用和客户端API相同的域名,可以直接使用缓存的DNS而不用再发起请求图片。静态资源同理。
- 跨域请求移除非必要自定义header,避免该请求发出预检请求。
- 预读取DNS
- 新增 dns-prefetch标签
- 用 meta 信息来告知浏览器,当前页面要做 DNS 预解析
- 在页面 header 中使用 link 标签来强制对 DNS 预解析
- 通过 CDN 向用户分发传输相关库的静态资源文件
- 多域名备份。服务端会下发多个 CDN 链接,当用户访问当前 CDN 节点的出异常时,可以快速自动切换到下个 CDN 节点。
- 快速超时策略
- minify / gzip 压缩
- HTTP 协议缓存静态文件HTML 和 JS/CSS/image
- 询问是否有更新:根据 If-Modified-Since / ETag 等协议向后端请求询问是否有更新,没有更新返回304,浏览器使用本地缓存。
- 直接使用本地缓存:根据协议里的 Cache-Control / Expires 字段去确定多长时间内可以不去发请求询问更新,直接使用本地缓存。
- 同步渲染时如果后端请求时间过长,可以考虑采用chunk编码,将数据放在最后,并优先将静态内容flush。可以让后端的API请求和前端的资源加载同时进行。
- 在HTTP协议中,我们可以在header中设置 transfer-encoding:chunked 使得页面可以分块输出。
- 让head部分都是确定的静态资源版本相关内容,而body部分是业务数据相关内容,那么我们可以在用户请求的时候,首先将Web API可以确定的部分先输出给浏览器,然后等API完全获取后,再将API数据传输给浏览器。
页面框架渲染(DOM下载、DOM解析、CSS请求+下载、CSS解析、渲染、绘制、合成)
- CSS不会阻止页面显示,内联的JS很快执行完成。当这两部分同时出现的时候,CSS加载阻塞下面的内联JS,而被阻塞的内联JS则阻塞HTML的解析。如果必须要在头部增加内联脚本,一定要放在CSS标签之前。
- 避免重排
- 增加或删除 DOM 节点;
- display:none(重排并重绘);visibility:hidden(重绘);
- 移动页面中的元素;
- 改变元素尺寸(宽、高、内外边距、边框等);
- 用户改变窗口大小,滚动页面等;
- 页面初始渲染;
- 改变元素内容(文本或图片等)。
- 离线包
- 将 JS 和 CSS 还有一些图片都内联到一个文件中,这样就只需要一次 IO 操作
- 高性能要求页面还是需要后端渲染(smarty)。相关推荐、广告等可以在内核渲染完后,执行JS,并利用preact进行异步渲染。
- 首屏静态资源预取缓存
- 资源内容的变化就一定会引起资源路径变化
- 给每个资源文件一个版本号或hash值,若资源文件有更新,版本号和 hash 值变化,这个资源请求的 URL 就变化了,同时对应的 HTML 页面更新,变成请求新的资源URL
JS解析、编译、执行
- JS代码的编译和执行会有缓存,同App中网页尽量统一框架。
- 脚本执行慢,就让脚本在最后运行,不阻塞页面解析。
- 脚本执行慢,可以把框架代码拆分出来,在请求页面之前就执行好。
图片
- WebP 格式
- 会将图片和视频等非文字内容通过原生组件的方式放在客户端进行渲染
- 借由内核的shouldInterceptRequest回调,拦截落地页图片请求,由客户端调用图片下载框架进行下载,并以管道方式填充到内核的WebResourceResponse中