iOS离线包加载分享

一、需求背景

为了提高用户体验,针对 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

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

推荐阅读更多精彩内容

  • 注:本篇研究重点不在于某个离线方案的具体使用,而在于对方案的优缺点分析、探究和选型,以及一些我个人的看法。 前言 ...
    LotLewis阅读 9,984评论 7 16
  • 背景 为了快递迭代、更新,公司app有一大模块功能使用H5实现,但是体验比原生差,这就衍生了如何提高H5加载速度,...
    edison0428阅读 914评论 0 1
  • 拦截原理 开发步骤 先使用本地的资源 不走加载 , 大量阅读业界秒开方案 做笔记 核心点记录 ios 和安卓出de...
    wg689阅读 929评论 0 1
  • 一、背景 由于公司业务大部分使用的H5去实现,而H5页面对网络的依赖也是比较大的。近期公司又提出需要界面秒开需求,...
    林风098阅读 3,217评论 2 3
  • KKQuickDraw iOS通过WKWebView、WKURLSchemeHandler协议实现HTML H5秒...
    今天星期伍阅读 9,991评论 0 15