离线包方案参考思考过程-总结了几篇文章

发布:admin2025-07-15 23:25:51 8241条浏览分类:世界杯怎么画

总结了下几篇文章

网易(资源离线/JsBridge通信/接口预请求)

网易新闻客户端H5秒开优化

H5优势: 跨平台, 实时更新, 便于传播等

劣势: 功能(硬件访问能力, 离线功能), 性能, 体验等

一. 资源离线

静态资源加载耗时, 资源离线到本地, 能很好解决.

web页面把静态资源生成zip包, 客户端在合适的时机拉去zip包并解压到本地, 持久化存储.

用户访问的时候拦截WebView发出去的页面请求, 直接返回对应的本地文件.

前端:

生成zip包 -> 更新离线数据

APP:

下载zip包 -> 拦截页面请求 -> 返回本地资源

三个关键部分:

Web页面Zip包生成工具

离线管理系统

客户端离线实现

web打包工具

{

[

"name": "index", // 页面名称

"url": ["https://example.com/index"] //页面线上地址

"zipUrl": "https://assets.example.com/static/example.20190525_1020.zip", // zip地址

"md5": "md5md5md5md5md5md5md5md5md5md5md5md5" // md5

]

}

工具自动化分成通过中间件实现

通用部分:

拷贝页面依赖, 生成zip包

判断包的完整性

获取zip包的md5值

生成zip包版本号

定制部分:

确定待更新zip包

上传zip包到cdn

更新离线数据, zip包版本数据

通用部分:

获取打包配置 -> 拷贝/打包 -> 检测包完整性 -> 获取MD5

定制部分: (可以在打包工具做, 也可以手动上传)

确定待更新包 -> 上传zip到cdn -> 更新数据

离线管理系统:

为离线工具提供打包信息及离线包信息存储

为App提供离线数据

页面离线数据在线管理

应该完成多产品, 多用户设计.

工具自动更新数据, 还可以在系统里添加数据, 对数据进行增删改查.

离线数据保留最近5个版本, 发现线上zip包有问题, 可以迅速回归.

核心功能:

多产品

多用户

在线操作

提供接口

客户端实现 (最重要)

离线资源更新

拦截资源返回

离线资源管理器总调度处理资源更新和拦截返回.

根据配置离线配置细腻创建动态管理器, 部署每个url对应的页面入口文件, 静态资源目录等.

更新app配置氛围主动和被动.

主动通过app启动后通过接口获取离线配置信息.

被动通过push更新.

获取离线配置后, 读取本地配置缓存进行对比.

根据页面名称确定离线文件的更新策略是什么.

远端配置无, 本地配置有, 认为当前页面离线包被删除. 直接删除本地对应的离线页面入口文件.

发现两个配置中同名页面zip包的md5不一致, 认为应该更新了.

如果发现远端有, 本地无, 则是新增, 然后交给下载管理器下载. 下载解压完成后, 通知管理器更新本地配置.

流程:

获取离线配置 -> 匹配资源 -> 确定更新策略 -> 更新资源和本地配置.

拦截返回细节.

统一拦截所有网络请求, 通过管理器处理访问逻辑.

需要拦截返回:

html

js, css, img

app在WebView发起请求时, 会拦截当前页面请求, 获取页面的URL地址, 根据管理器中的配置, 进行查找.

找到直接返回入口文件

未找到请求线上地址

页面的加载会伴随着依赖资源的加载, 获取请求url, 如果在拦截域名内, 则替换域名为本地的静态资源目录进行查找.

找到后, 获取文件扩展名, 设置返回的文件类型直接返回.

拦截并返回本地资源

& 返回本地资源

& 获取离线配置 -> 匹配请求地址 -> -> 渲染Web页面

& 请求线上资源

app针对每个环节出现的错误进行上报:

离线相关的错误类型有:

获取离线配置接口网络错误

获取离线配置接口数据解析失败

zip包请求网络

zip包解压错误

zip包md5值app端与前端不一致

zip包解压手机空间不足

任何一种错误都不会更新本地离线资源和离线配置.

一. JSBridge

大部分业务需要的native功能

视图层面: 注册, 登录, 认证, 注销组件, 视图路由

存储层面: 用户信息, 设备信息, 业务状态, 缓存

网络层面: 请求header, 代理转发, 预请求

app层面: 唤起, 设置, push, 跨app操作

系统层面: 底层api的调用

其他辅助功能.

...其他的不属于离线包, 暂不处理...

一. 实际应用

请求代理

预请求

统一业务header

统一日志管理

跨域

WebView预创建

二.移动端本地 H5 秒开方案探索与实现》

参考: 移动端本地 H5 秒开方案探索与实现

适用场景: 需要快速迭代, 客户端难以实现的, 用作展示的功能模块, 例如可视化图表.

二.为什么体验糟糕

过程:

初始化webview -> 请求页面 -> 下载数据 -> 解析HTML -> 请求js/css资源 -> dom渲染 -> 解析js执行 -> js请求数据 -> 解析渲染 -> 下载渲染图片

一般页面在dom渲染后才能展示, 可以发现, H5首屏渲染白屏问题关键: 如果减少从请求下载页面到渲染之间这段时间的耗时.

二.如何优化

优化常用方式:

降低请求量: 合并资源, 减少HTTP请求数, minify/gzip压缩, webP, lazyLoad

加快请求速度: 预解析DNS, 减少域名数, 并行加载, CDN分发

缓存: HTTP协议缓存请求, 离线缓存mainifest, 离线数据缓存localStorage.

渲染: js/css优化, 加载顺序, 服务端渲染模板直出.

直接打包H5相关页面到客户端中, 然后客户端将数据传递给页面, 通过webView加载展示. 不需要网络请求, webView只要渲染页面, 执行js即可.

二.实现

H5和native通信

jsapi: 客户端提供接口, 注入api让js调用, 直接执行相应的native代码, 适用于需要通过交互, 进行数据请求的场景

url scheme: web端发送url scheme请求, 之后native拦截请求并根据url scheme以及所带参数进行相关操作. 使用页面跳转.

字符串替换: 客户端读取本地H5后, 通过对h5中约定的标记位进行字符串替换. 然后加载展示页面. 适用于没有复杂交互, 只通过页面渲染数据的场景.

开发本地H5模块, 本地模拟数据开发, 然后H5给各客户端打包后联调. 繁琐, 因为给客户端打包时比较分散, 不统一, 管理困难.

本地h5实现模块的页面建议一个统一git仓库, IOS和android客户端通过git submoduleGit Submodule使用完整教程将本地h5的git外链到项目中, 客户端中的资源就可以统一管理了, 解放了每次都手动繁琐替换打包工作.

H5资源给到后台, 客户端按照业务模块预下载整个离线包, 离线包根据版本做增量更新.

二.细节

预加载webView, 预拉取数据

屏蔽webView HTML内容自动识别

点击延迟

国际化

WKWebView兼容

WKWebView性能相对UIWebView较好. 推荐使用

WKWebView加载本地的HTML时, 会有兼容问题, 在IOS8不能在HTML文件中引用本地的css或者js或者图片文件.

ios8以上是正常的, 可以引用远程资源.

ios8使用网络资源, ios8以上使用本地资源.

ios8中, 使用远程cdn的css或者js文件, 引用标签必须添加charset属性. 不然css和js乱码.

三.蚂蚁离线包简介

离线包简介

传统的H5技术容易受到网络环境影响, 因而降低H5页面性能. 离线包可以解决该问题, 同时保留H5的优点.

离线包是将包括HTML, JavaScript, css等页面的内置静态资源打包到一个压缩包内. 预先下载该离线包到本地, 然后通过客户端打开, 直接从本地加载离线包.

优势:

提升用户体验: 通过离线包的方式把页面内置静态资源嵌入到应用中并发布, 当用户第一次开启应用的时候, 就无需以来网络环境下载该资源. 而是马上开始使用.

实现动态更新: 在推出新版本或是紧急发布的时候, 可以把修改的资源放入离线包, 通过更新配置让应用自动下载更新. 无需通过应用商店审核, 就让用户及时接收更新.

三.离线包结构

离线包是一个.amr格式的压缩文件, 后缀.amr改成.zip解压后, 可以看到其中包含了HTML资源和JavaScript代码等. 待H5容器加载完成后, 这些资源和代码能在WebView内渲染了.

一级目录: 一般资源包的ID, 例如20150901

二级目录及子目录: 业务自定义的资源文件. 建议所有前端文件保存在一个统一目录下.

* 20150901

* hmpfile.json

* sdk

* www

* index.html

* js

* test.html

* 20150901.tar

* CERT.json

* Manifest.xml

三.离线包类型

基础通用库使用全局离线包.

类型:

全局离线包: 包含公共资源, 可供多个应用共同使用

私有离线包: 只可以被某个应用单独使用.

使用全局离线包后, 在访问H5的时候, 都会尝试在这个包读取. 如果该离线包里有对应资源的时候, 直接从该离线包里读取, 而不通过网络. 因此全局离线包的机制主要是为了解决对于通用库的使用.

由于要保证离线包的客户端覆盖率以及足够的通用性. 此包一般更新周期至少为一个月, 并严格控制离线包大小.

三.渲染过程

H5容器发出资源请求时, H5容器或截获该请求:

如果本地有资源可以满足该请求, H5容器会使用本地资源.

如果没有可以满足请求的本地资源, H5容器会使用线上资源.

无论资源使用线上或者是本地的, WebView都是无感知的.

离线包的下载取决于创建离线包时的配置

如果"下载时机"配置为仅WiFi, 只有wifi网络时才会下载.

如果配置为"所有网络都下载", 会消耗用户流量自动下载, 慎用.

如果当前用户点击app时, 离线包尚未下载完成, 则会跳转到fallback地址, 显示在线页面.

fallback技术用于应对离线包未下载完毕的长江. 每个离线包发布时, 都会在CDN发布一个对应的线上版本. 目录结构和离线包结构一致.

fallback地址会随离线包信息下发到本地. 在离线包未下载完毕的场景下, 客户端会拦截页面请求, 转向CDN地址. 实现在线页面和离线页面随时切换.

三.离线包运行模式

请求包信息: 从服务端请求离线包信息, 存储到本地数据库过程. 离线包信息包括离线包的下载地址, 离线包版本号等.

下载离线包: 把离线包从服务端下载到手机.

安装离线包: 下载目录, 拷贝到手机安装目录.

三.虚拟域名

虚拟域名仅对离线应用有效, 当页面保存在客户端之后, WebView通过file schema从本地加载访问的. 然而用户就能在地址栏里直接看到file的路径:

用户体验问题: 当用户看到file地址, 会对暴露的地址产生不安全感和不自在.

安全性问题: 由于file协议直接带上本地路径, 任何用户都可以看到这个文件所有的路径, 会存在一定的安全隐患.

所以采用虚拟域名的机制. 而不直接使用file路径访问. 虚拟路径是一个符合URL Scheme规范的HTTPS域名地址, 例如: https://xxxxxx.h5app.example.com, 虚拟域名的父域名example.com一定得使用自己注册的域名

这个域名可以是网上注册的, 但是一般情况下, 不建议将虚拟域名配置成互联网一致的域名, 这个在判断问题的时候, 容易增加判断难度, 容易出错不便于日常管理. 只要保证其父域名example.com域名是自己注册的域名即可.

标准的虚拟域名如下: https://{appid}.h5app.example.com

四.蚂蚁生成离线包

参考: 生成离线包

根据不同需求, 将不同业务封装成为一个离线包, 通过发布平台发布对客户端资源进行更新.

生成步骤:

构建前端.zip包

在线成才.amr包

四.构建前端.zip包

根据场景不同: 配置路径分为:

全局资源包

普通资源包

同一个H5离线包中, 全局资源包于普通资源包不可共存.

离线包ID(下文中的一级目录), 必须为8位数字.

四.全局资源包

可以将被其他多个资源包引用的通用资源放置在全局资源包内, 并按照下列规则指定包内的资源路径

一级目录: 全局资源包的ID: 如77777777

二级目录: 指向资源可访问的服务器域名地址.

公有云: 固定为mcube-prod.oss-cn-hangzhou.aliyuncs.com(离线包管理->新增离线包页面的资源包类型中可看到相关提示信息)

专有云: 请查询专有云部署的mdsweb服务器域名地址

三级目录: appid_workspaceId, 例如: 53E5279071442_test

三级目录往后即为业务自定义的公共资源文件. 在公共资源文件的文件夹名, 文件名以及文件中, 避免使用特殊字符. 特殊字符会被urlencode函数转换字符

以上规则组织资源文件后, 即可按照如下格式快速获取资源文件的路径:

公有云: http://域名/appid_workspace/资源文件路径

专有云: http://域名/mcube/appId_workspace/资源文件路径

示例:

在公有云中: 二级目录固定为: mcube-prod.oss-cn-hangzhou-aliyuncs.com, 所以下图中资源文件common.js路径为: https://mcube-prod.oss-cn-hangzhou.aliyuncs.com/53E279071442_test/common.js

在专有云环境中, 二级目录为专有云部署的mdsweb服务器域名地址, 此外mdsweb-outer.alipay.net为例. 下图资源文件common.js的路径为https://mdsweb-outer.alipay.net/mcube/53E5279071442_test/common.js

注意实现:

公共资源的绝对路径长度不超过100字符, 否则会导致客户端加载资源失败以及页面白屏

服务端未控制全局资源包版本, 用户可根据实际需求, 通过在三级目录以后添加文件目录结构的方式, 来自定义控制文件的高低版本.

在专有云环境中, 如果服务端采用的文件存储格式为HDFS或AFS, 则需要在上述第三级目录前增加一个目录, 该目录名称为mdsweb目录, 该目录名称为mdsweb服务器中的存储空间(bucket)的名称.

引用公关资源: 在普通离线包内访问全局资源包中的内容, 必须通过绝对路径访问, 如: https://mcube-prod.oss-cn-hangzhou.aliyuncs.com/53E5279071442_test/common.js

四.普通资源包

按照业务将相关的HTML, CSS, JavaScript, 图片等前端资源放置在同一个离线包内, 目录结构如下:

一级目录 普通资源包的ID, 如20171228.

二级目录及往后即为业务自定义的资源文件. 建议在所有的前端文件最好保存一个统一的目录下, 如/www, 并设定当前离线包默认打开的主入口文件, 如: /www/index.html

.

配置万资源包的路径后, 即可直接将appid所在的目录整体压缩为一个.zip包.

四.在线生成.amr包

进入控制台的实时发布->离线包管理页面, .zip包上传到MDS发布平台, 生成.amr包.

五.H5秒开方案大全

五.常用的加速方法

资源加载:

针对首屏

更小的资源包

压缩, 减包, 拆包, 动态加载包, 图片优化

html渲染:

针对可优化

更快的展示内容

cdn分发, dns解析, http缓存, 数据预请求, 直出

rn, weex, flutter冲击传统hybrid, hybrid加速发展.

五.直出+离线包缓存

直出: 后端渲染, 省去了ajax请求时间, 能够通过各种缓存策略优化很好, 加载html扔需要时间.

离线包技术: 解决html本身加载需要的时间问题.

离线包基本思路通过通过webview统一拦截url, 将资源映射到本地离线包, 更新的时候对版本资源检测, 下载和维护本地缓存目录中的资源.

对于web端而言: 相对透明, 侵入性比较小.

五.客户端代理的VasSonic 腾讯手 Q VasSonic 秒开

用户点击到看到页面之间, 存在webview初始化, 请求资源的时间, 这里的过程是串行的, 所有存在优化空间.

支持离线包策略, 并更进一步

webview初始化和通过客户端代理资源请求并行

流式拦截请求, 边加载边渲染

实现了动态缓存和增量更新

客户端代理请求并行:

创建webview之前, 通过客户端代理建立网络链接, 请求html, 然后缓存起来.

等待webview线程发起请求html资源的时候,客户端拦截, 将缓存的html返回给webview

动态缓存和增量更新:

自定义了一套标签. 将html区分为模板和动态数据两部分.

拓展了http头部, 定制了一套请求后台的约定

webview发情请求的时, 会将页面内容的id携带过去, 后台判断后, 再告诉客户端是否更新局部数据

如果是缓存额html模板和新数据拼接成新的html, 最后计算差异部分, 通过js回调给页面, 进行局部刷新

通过模板可以达到局部变化, h5秒开结果.

但定义了一套特殊的注释标记及拓展了头部, 需要包括后台在内的前后端进行改造. 对web入侵性非常强. 维护成本高.

五.PWA+直出+预加载

不管是离线包技术, 还是webview代理请求, 都对前端入侵比较大.

pwa能够通过纯web的方案优化加载性能.

对于直出html, 配合pwa, 直出文件, 缓存到cacheStorage, 在下一次请求时, 优先从本地缓存中读取, 同时发起网络请求更新本地html文件.

第一次加载通过app预加载一个js脚本, 拉去需要pwa缓存的页面, 可以提前完成缓存.

非直出页面.

第一次只能提前加载. 预加载脚本.

第二次非直出页面, 每个页面需要有独一无二的标记, 比如hash. 浏览器获取到数据, 渲染好的html, 通过outerHtml方法, 将html缓存到cacheStorage中.

第二次优先从本地获取, 同时发起html请求, 通过对比其中唯一标识的差距, 决定是否需要更新.

pwa一系列方案替代离线包, 属于web标准, 适用于普通能够支持service-worker的H5页面.

在兼容问题允许的情况下, 建议主加.

五.NSR渲染

前端SSR

借住浏览器启用一个JS-Runtime, 提前将下载好的html模板及预取的feed流数据进行渲染. 然后将html设置到内存级别的MemoryCache中, 从而点开即看.

NSR将SSR渲染过程分发到各个用户的端. 减少后台请求压力, 进一步提高页面打开速度.

数据预取和预渲染带来的额外流量和性能开销, 特别是流量. 如何更准确的预测用户行为, 提高命中率非常重要.

五.客户端PWA

service-worker在webview实现性能并没有想象中好.

五.小程序化

小程序内部将webview渲染和js执行分离开, 然后通过离线包, 页面拆分, 预加载页面等手段

牺牲了web的灵活性.

对于hybrid开发, 通过原生客户端底层支持小程序环境, 大量业务逻辑采用小程序方案开发

迭代速度和性能兼容, 是一个不错方向

五.总结

在整个链路中减少中间环境, 例如串行改并行, 包括小程序内部执行机制.

尽可能预加载, 预执行. 比如从数据拉去, 到页面渲染.

任何转换都有代价, 加速本质上就是在用更多的网络, 内存和CPU换取速度. 以时间换空间

六.转转hybrid app web静态资源离线系统

六.前言

优点:

web页面上线满足快速迭代的业务需求, 不收客户端审核和发版的时间限制.

也可以将各个业务线的开发工作分摊到各个业务的fe团队上, 是的业务线并行开发.

缺点:

web应用的性能和体验, 不及客户端.

痛点1:

打包后静态资源过大, 首次打开/线上H5资源更新/网络条件差/本地页面缓存失效.

白屏.

痛点2:

app使用系统原生的web view, 不兼容pwa.

各个业务团队使用的技术栈比较广. 各个业务线快节奏开发, 需要低成本接入. 对业务代码不会产生入侵.

六.方案

前端构建发布:

ak-webpack-plugin: 根据配置, 将webpack的构建出的静态资源, 压缩成了静态资源在cdn路径url的zip包, 同时在配置的过程中, 可以选择排除掉部分文件.(例如, 部分图片)

不需要关注资源之间的依赖关系, 更不需要关注具体的业务逻辑.

只需要关注webpack构建后生成的资源文件夹的结构.

使用jenkins.持续集成和发布.

app:

预置一份最新的各个业务线的离线包与版本号的配置表.

app启动时, 会将压缩包解压到手机rom中, 各业务线配置中包含app访问线上的静态资源时需拦截的url规则map:

当app访问到与规则map相匹配的地址时, 就转为本地资源, 达到离线访问目的.

[{

"bizid": 13,

"date": "1513681326579",

"ver": "20171219185710",

"offlinePath": [

"c.58cdn.com.cn/youpin/activities"

]

}]

离线资源如何更新

客户端启动后, 向离线系统查询最新的各个业务的离线包版本号, 依次跟本地配置中的对应业务线比较.

如果需要更新, 则再次向离线系统查询此业务线的离线包信息. 离线系统会提供此业务线的离线包的信息.

判断是否需要更新:

线上的各业务线的离线包版本号与本地配置中 同一业务线的配置不同(不论最新的离线包版本比本地更高或者更低)

线上的各业务线的配置中包含本地配置没有配置的业务线.

六.离线包加载优化

增量的资源更新 (bsdiff/bspatch)

影响bsdiff生成的差分包的体积因素主要有:

zip包的压缩等级

zip包中文件内容的修改. 比如js进行了uglify压缩, 变量名的变化可能引起大幅的变更.

可以减少客户端升级离线资源需要下载的流量

单独控制各个业务线web应用是否使用离线机制

每个业务都加入使用离线资源的开关和灰度放量的控制.

数据一致性校验 与 数据安全性校验.

防止下载离线资源在传输中被篡改, 使用md5验证.

同时保证传输过程中, 资源文件不被篡改, 将md5值通过rsa加密算法进行加密, 在服务端和客户端分别使用一对非对称的密钥进行加解密.

批量下载:

启动app后, app会集中批量下载各个业务线的离线包资源, 在cdn中使用http2协议, 一次链接, 下载所有资源. 离线包个数较多的情况下, 可以比传统http1有更快的传输速度, 同时, 客户端只需要运行一次下载器. 减少多次运行下载对手机cpu损耗.

六.回退机制 fallback

可能出现的问题:

本地内置的base包(zip文件)解压失败

离线系统接口超时

下载离线资源失败

增量的资源合并失败等情况

六.离线资源管理平台

功能:

查看和管理各个业务线信息及其离线功能的灰度放量比例.

通过业务线, 版本号, 发布时间等条件. 查询各个版本的离线包资源列表及其详细信息

针对全局离线功能, 提供了离线功能开关.

允许将某个版本的离线包下线, 以实现离线资源版本的回滚功能.

六. 技术选型

离线系统的服务端使用nodejs实现.

使用轻量的koa框架.

使用log4j进行node日志的采集和记录.

使用轻量的nosql数据库mongdb记录离线包的数据信息. 使用对象模型工具mongoose进行nosql操作

md5的加密, 使用node-rsa库进行非对称密钥的生产, 操作和加密解密处理.

前端离线系统的后台页面, 使用vue与组件库iview.

压力测试: 使用压力测试工具siege.

建立性能监控系统, 运行稳定性/承载的压力/占用服务器硬件资源情况.

六.运行情况

cpu使用率

应用内存使用量

页面静态资源加载(js, css)耗时

页面可操作时间耗时

六.展望

下载引擎优化

断点续传/分块下载

离线资源的统计

node api层/cdn的nginx层实施

pwa技术

通过接入其他更强大的浏览器内核实施

七.今日头条品质优化:图文详情页秒开实践

今日头条品质优化:图文详情页秒开实践

七.数据建立

页面加载时间 = 页面加载完成时间 - 页面开始加载时间

页面开始加载时间: 点击了Feed上的卡片.

loadFinish回调不能反映用户的真是体验.

WebView渲染步骤:

解析HTML文件

记载JS和css文件

解析并执行js

构建DOM结构

加载图片等资源

页面加载完成

用户真实角度: dom结构构建完成(domReady)的时间点作为页面加载完成

七.白屏

对webview进行截图, 遍历截图的像素点的颜色值.

ios提供了webview快照的接口获取当前webview渲染的内容, 底层异步回调, api耗时10ms.

android中提供获取视图内容结构为getDrawingCache, api耗时40ms

webview截图的图片进行缩小到原图1/6, 遍历检测图片的像素点, 非白色像素点大于5%的时候, 认为非白屏情况, 可以相对高效检测准确得出详情页是否发生了白屏

七.指标建立

明确问题: 什么指标可以反映用户刷头条时的真实体验

最开始: 页面平均加载时长: 页面加载时长总和 / 页面pv

平均加载时长虽然可以反映详情页加载速度, 但因为详情页的pv比较高. 如果使用平均加载数度, 很多用户体验问题, 都被忽略掉了. 并不能反映用户的真实情况.

调整口径: 所有用户进入详情页的80分位值

80分为值是1s, 说明80%用户进入详情页都能在1s内加载完成.

优化目标为 80%用户, 0.3s加载完成.

后来提高到95分位

七.模板优化

模块拆分:

点击后的过程:

线上页面加载用户每次进入详情页都要多次网络加载, 极容易受到网络波动影响, 无法保证页面加载的时长和成功率, 极大的影响用户体验.

于是, 在头条中, 我们将新闻中标题和正文内容分开, 把头条详情页的公共样式css和逻辑js都抽离出来, 形成一个独立而完备的详情页模板, 可以把模板内置到客户端中(这不就是离线包吗.)

同时和前端约定好js脚本, 通过接口将正文内容数据注入页面完成详情页的页面展示, 通过这种方式可以将接口放到客户端上请求.

客户端通过一定策略预加载新闻数据, 在理想状态下用户进入页面看到页面时,就可以直接使用缓存的数据. 用户在看新闻的时候可以完全实现离线化, 避免受到网络的影响.

模板预热:

全流程离线化之后, 页面加载的瓶颈变成本地模板加载, 优化本地模板加载.

模板合并: 加载完html再去加载js和css, 需要多次io操作, 于是把js和css还有一些图片都内联到一个文件中, 加载模板就只需要一次io操作.

模板简化: 将非必须的脚本异步拉取, 精简不必要的样式和JS代码, 将模板大小压缩了20%以上.

模板和数据分离后, 用户点击的时候加载的是同一个模板, 实际上, 我们并不需要在用户进入页面的时候去创建webview以及加载模板

只需要在合适的时机在后台创建webview, 并且提前预热模板.

用户进入页面的时候, 就能使用已经加载好模板的webview, 直接将详情页的内容数据通过js注入到页面中. 前端收到数据, 渲染即可.

模板复用:

95分位看实际数据优化并不明显, 从数据上观察, 用户预热模板的命中率只有53%, 可进一步提升.

为了尽可能提高页面加载速度, 我们希望用户每次进入详情页都能够使用预热好的webview, 模板预创建池手段优化用户进入详情页时的预热模板命中率.

webview的创建是一个性能开销比较大的操作, 使用雨创建池的方案, 就会在后台频繁创建webview, 这样对用户在feed场景的浏览提体验也会有一定影响.

每次使用同一个模板, 用户退出页面后, 把正文数据清空, 进入下一个页面的时候能够继续复用这个webview, 重新注入数据即可

避免了后台创建webview对用户刷新feed体验, 又提高了预热模板命中率.

七.网络优化

CDN加速

容灾

七.渲染优化

服务器端预渲染:

服务器端把所有的详情页正文的HTML数据组装好, 通过将服务端直出内容注入到页面中. 直接给webview渲染.

客户端渲染:

webview渲染非文字部分存在一下问题:

渲染效率差

大量图片, webview的渲染内容占用, 滑动体验

多次打开同一篇文章, 多次加载问题, 无法与客户端进行缓存共享.

图片和视频等非文字内容通过原生组件放在客户端进行渲染, 提高渲染效率, 减少流量

多图文章, feed页面, 只能加载详情页需要的图片, 增加用户的文章首屏体现.

白屏优化

ios中, 我们使用系统自带的WKWebView, 一个运行在独立进程中的组件, 所以, 内存过大的时候, WKWebView所在的WebContentProcess会被系统kill掉, 反映出来就是白屏

根据WKWebView提供的回调webViewWebContentProcessDidTermainate函数进行reload重新加载. 因为是模板, 没有办法注入数据.

尝试重新注入时间很长. 在注入脚本中判断是否存在数据注入接口, 如果不存在, 直接重试.

android, 使用自研内核webview

多线程读模板问题, webview在运行中会读取的文件模板, 此时如果另一个线程同时更新模板文件, 就出现了模板加载问题, 需要保证模板加载的原子性.

Render卡死问题, 内部渲染可能会出现Render卡死问题. 从业务上做白屏监控进行重试.

不管是IOS和Android, WebView加载逻辑都比较复杂, 重试页无法成功时, 会降级加载线上的详情页, 优先保证用户的体验.

七.总结

数据很重要: 优化加载之前第一件事, 就是建立一个详情页的数据看板, 只有通过数据, 我们才能了解目前线上用户的现状, 从真实用户的体验找到瓶颈和优化点.

用户体验优先: 优化方案很多, 除了加载速度之外, 需要从整体应用体验出发, 选择对用户最佳的方案

追求极致: 扣细节, 到极致.