美文网首页
iOS离线包加载分享

iOS离线包加载分享

作者: libtinker | 来源:发表于2024-03-11 15:48 被阅读0次

一、需求背景

为了提高用户体验,针对 APP 内嵌的 H5 页面,有一种比较常见且有效的方式就是接入离线包,通过把页面加载需要的静态资源提前下载到客户端本地,避免页面加载时静态资源网络请求的开销,从而来提高页面的加载速度。

二、知识储备

1.webview加载h5的过程:

打开一个h5页面通常会有较长时间出现白屏,以及几秒后出现内容,在这几秒中到底做了什么事情?因为在这其中做了很多事情,大约包括:

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


企业微信截图_356e5c7f-df4a-4e61-a5f4-3839285ea6fa.png

一般来说, Webview渲染需要经过下面的几个步骤:

  1. 解析HTML文件
  2. 加载 JavaScript 和 CSS 文件
  3. 解析并执行 JavaScript
  4. 构建 DOM 结构
  5. 加载图片等资源
  6. 页面加载完毕

一般页面是在dom渲染后才能展示,h5首屏渲染白屏问题的原因关键在于,如何去优化请求下载->渲染之间的耗时成了重点.

2.WKWebView拦截请求:

研究了业内已有的 WKWebView 请求拦截方案,主要分为如下两种:

NSURLProtocol

NSURLProtocol是一个抽象类,作为URL Loading System系统的一部分,能够帮助我们拦截所有的URL Loading System的请求,在此进行各种自定义的操作,是网络层实现AOP(面向切面编程)的利器。

WKURLSchemeHandler

WKURLSchemeHandler 是 iOS 11 引入的新特性,负责自定义请求的数据管理,如果需要支持 scheme 为 http 或 https请求的数据管理则需要 hook WKWebViewhandlesURLScheme: 方法,然后返回NO即可。

两种方案对比

| NSURLProtocol | WKURLSchemeHandler |
| 隔离性 | 一经注册就是全局开启。使用了 NSURLProtocol 的方式后会导致应用内合作的三方页面也会被拦截从而被污染。 | 可以以页面为维度进行隔离,可以通过WKWebViewConfiguration 进行配置。 |
| 稳定性 | NSURLProtocol 拦截过程中会丢失 Body | WKURLSchemeHandler 在 iOS 11.3 之前 (不包含) 也会丢失 Body,在 iOS 11.3 以后 WebKit 做了优化只会丢失 Blob(二进制的一种数据类型) 类型数据 |
| 一致性 | WKWebView 发出的请求被 NSURLProtocol 拦截后行为可能发生改变,比如想取消 video 标签的视频加载一般都是将资源地址 (src) 设置为空,但此时 stopLoading 方法却不会调用 | 表现正常 |

****结论:****WKURLSchemeHandler在隔离性、稳定性、一致性上表现优于NSURLProtocol,但是想在生产环境投入使用必须要解决 Body 丢失的问题。

三、技术实现

H5离线包的基本原理是将html、js、css、图片等静态资源打包成压缩包,然后下载到客户端并解压,H5加载时直接从本地读取静态资源文件,减少网络请求,提高速度。

3.1 总体流程

222.png

客户端启动后,先去远程配置服务器拉取离线包相关的功能配置,然后检查更新,如果有更新则下载离线包。webview加载时,如果本地缓存命中,则从本地磁盘加载html、js、css、图片等静态资源。。

3.2 离线包和非离线包对比

webView最简单的做法是直接通过URL去加载一个线上页面。当从浏览器输入一个URL到页面中间经历了什么?

3333.png

从上面看出用户加载一个web页面都要经过多次网络加载,中间是极易受到网络波动的影响,在无法保证页面加载的时长和成功率的情况下,会很大影响用户体验。

于是把html、js、css都抽离出来做成离线包放在本地,这样加载一个web页面的过程就如下图

4444.png

3.3 行业方案

| 方案名 | 优点 | 缺点 | 备注 |
| 加载本地路径 | 简单可靠,无需hook和调用私有API | 有跨域问题,影响cookie和localstorage,H5需做少量改动 | 货拉拉方案 |
| 请求拦截 | 不修改加载URL,没有跨域问题,且支持网页部分资源离线化,灵活性和兼容性好 | iOS端目前提供的NSURLProtocol和WKSURLSchemehandler拦截方案有缺陷,前期实现成本高 | 网易云音乐方案zhuanlan.zhihu.com/p/347592487 |
| 本地Web Server | 兼容性好 | 对客户端耗电和CPU性能有影响 | 暂未发现有公司采用,juejin.cn/entry/68449… |
| Service Worker | 前端兼容性好 | iOS端WKWebView不提供官方支持,实现技术难度大 | 爱奇艺方案zhuanlan.zhihu.com/p/148931732 |

四、接入工作:

目前我们采用的方案是:本地文件路径(file://协议),可能存在一些问题,所以在接入离线包前,我们需要对 H5 项目进行改造。

4.1 问题和解决办法

| 存在问题 | 解决方法 |
| cgi 请求跨域问题 | 在网关或者后端服务的跨域请求头增加 null 域支持 |
| cookie 跨域问题 | 我们接入的项目中无 cookie 操作,如果有的话,需要改成用请求 header 的方式。 |
| localStorage 跨域问题 | 我们接入的项目中 localStorage 不涉及域名隔离问题,如果有需要,可以采取调用原生的方式来做前端存储。 |
| 资源引用的绝对路径在离线包模式下不支持 | 改成相对路径 |

4.2 接口跨域处理

目前我们线上模式的请求链路大致为H5 → 网关 → 后台服务,大部分的项目都是通过一级通用网关来处理跨域问题,但是由于离线包模式下需要网关设置允许 origin: null 的场景跨域,直接在通用网关处理可能存在安全问题。

目前我们的实现如下:

通过hook header["是否是接口请求"]判断是否拦截请求,然后替换根据header["x-request-host"]来替换当前的host;一句户就是app帮助h5请求网络再把结果回调给h5。

五、参考资料

苹果官方文档https://developer.apple.com/documentation/webkit/wkwebview?language=objc

货拉拉H5接入离线包的实践总结 zhuanlan.zhihu.com/p/538288299

WKWebView之离线加载以及遇到的问题https://blog.csdn.net/Lu_Ca/article/details/125723040

WKWebview秒开实践分享及问题解决方案(抖音)https://juejin.cn/post/6887161842406260744#heading-6

WKWebView 请求拦截探索与实践(网易)https://juejin.cn/post/6922625242796032007

相关文章

网友评论

      本文标题:iOS离线包加载分享

      本文链接:https://www.haomeiwen.com/subject/bovmzdtx.html