1.1.1 离线包
1.产生背景
mPaaS移动开发框架提供了一套完整的混合应用(Hybrid)开发解决方案,包括客户端的H5容器组件和服务端的离线包发布管理平台。H5 Web应用的特点是开发效率高,但受制于Web技术和HTTP协议的限制,在移动端的表现差强人意。Native应用的优势在于性能,但是动态更新的能力较弱。Hybrid方案的出现正是为了调和这两者矛盾并发挥两者的优势,其核心技术能力包括:H5离线技术和JSBridge技术。简单来说,H5离线技术就是将HTML/CSS/JS和资源文件等打包提前下发到App中,使得App在加载H5应用时可以直接从本地读取资源文件,避免了大量的网络资源请求,从而提高H5应用的加载效率。JSBridge技术则提供了H5应用和Native应用直接沟通的桥梁,进一步的增强H5应用的拓展能力。Hybrid方案下的H5应用与传统Web应用在加载和运行机制上的差异给开发过程中的问题排查带来了诸多难点,本专题就H5容器与离线包相关的问题和排查方式做专门的介绍。
2.基本原理
在这一节,我们抛开代码细节,从朴素直观的层面去理一下mPaaS H5离线技术的基本设计和运行原理。
1)离线包分类
如图1-1所示,在mPaaS中有两种离线包,一种是普通资源包,另一种是全局资源包。
2)普通资源包
从web的角度看,一个普通资源包就是一个普通H5 Web应用的所有内容,包括HTML/JS/CSS等资源文件。在实践中,不同的业务模块可以拆分成不同的H5 Web应用站点,这些App可以独立开发,相互不干扰。如果把这些App部署在Internet上,是可以通过浏览器或者Webview正常访问和使用的。如前面所说,为了提高性能,我们可以把这个App的资源提前部署到移动端,访问这个站点时,直接在本地加载资源到H5容器中(浏览器),从而消除通过网络加载资源所带来的开销和副作用。mPaaS提供了一个这样的方案:允许开发者将一个H5应用按照一定的目录格式打包成一个离线包,通过发布平台下发到客户端,客户端再解压和加载离线包中的资源文件。
3)全局资源包
不同业务模块,也就是不同的H5站点,可能引用了一些共同的资源文件,如通用的JS库文件、共享的UI资源等。为了进一步压榨性能,可以把这些共享的资源放在一个独立的全局资源包中,当不同的业务包需要读取这些资源时,都从同一个独立资源模块中加载。提高了资源的付用率,进一步压缩普通包的体积。
图1‑1 离线包介绍
3.资源离线
要在客户端实现Web资源的离线化,mPaaS客户端框架需要解决哪些问题?
1)如何标识离线资源
如图1-2所示,mPaaS要求开发者为应用配置一个全局的“虚拟域名”,如h5app.example.com;并为每一个H5 App配置一个appId。框架会在客户端维护一个appId与App离线资源的映射关系,当客户端试图通过appId去加载一个H5应用时,H5容器会根据这个映射关系在本地获取对应的站点资源文件,并使用https://{appid}.h5app.example.com这个虚拟的域名地址在Webview中加载H5站点资源。
图1‑2 资源离线介绍
2)如何更新离线资源
当站点在Internet上时,由于客户端是通过HTTP协议获取的这些资源,HTTP协议机制保证了客户端每次都可以拉取到最新的资源文件。在资源离线时又该如何处理?当一个H5应用需要更新时,开发者通过mPaaS离线包发布平台上传这个H5应用的更新包,并赋予一个新的版本号。在客户端,App会主动询问服务端某个H5应用的离线包是否存在版本更新,如果有,服务端会告知客户端更新包的详细信息,客户端则根据信息按需主动下载新的资源包到本地并解压覆盖之前的离线资源文件,从而实现离线资源的更新。
3)离线资源的预置
通过网络下载离线包可能并不能满足所有的场景,在某些情况下(如无网,弱网,App初次安装等),如何进一步提高H5应用的用户体验?mPaaS允许开发者将离线包预置到App中,使得应用在安装后就直接拥有了部分离线资源,保证了H5应用的启动性能和用户体验。
4)离线包的安全性保障
如图1-3所示,为了保证离线包的安全,开发者可以开启离线包验签功能。验签的基本过程如下:
(1) 开发者配置好一对共私钥,私钥放在服务端用于对离线包进行签名,公钥放在客户端,用于对签名对验证;
(2) 在离线包发布平台,如果配置了签名私钥,平台下发的amr文件就会带上签名信息;
(3) 客户端在拿到amr包并解压后,客户端会使用在项目中预置的公钥进行签名的验证,如果相同则通过验证。
该过程保证了即保证了离线包的内容完整,也保证了离线包的来源正确。
图1‑3 离线包签名校验
5)离线失败的处理
客户端的运行环境复杂,各种情况层出不穷,如果资源离线化“失败”怎么办?mPaaS的离线技术提供了fallback机制,当离线资源获取失败时,允许客户端从指定的在线地址上获取对应的资源,保证H5应用的正常使用。
图1‑4 fallback机制
4.加载过程
离线包的加载过程如图1-5所示。
图1‑5 离线包加载流程
5.常见问题
根据离线包的技术特点和历史经验,与离线包相关的问题症状非常多,包括:页面完全打不开,页面打开白屏,页面资源加载不正常,内容渲染不正确,页面功能不正常,资源不是从本地获取而是从线上获取,离线包无法更新等问题。
从类型上看,大致有三个大类:
1)加载失败
2)更新失败
3)离线失败(没有走本地资源)
从问题发生的位置上看,问题可能来自以下几个方向
1) 客户端
容器本身错误;前端代码错误;离线包验签错误;代码逻辑错误;组件bug。
2) 服务端
离线包发布错误;离线包配置错误;后端bug。
3) 网络层面
中间设备问题;SSL握手问题;TCP连接问题。
授人予鱼不如授人予渔。这里暂不详细解释各种问题和原因的细节,在实际的开发生产过程中,开发者遭遇的问题更是层出不穷、千奇百怪。回归本源,我们首先观察一下正常的情况下,离线包的各种行为应该是什么样。
6.从网络包看离线包流程
1)单个离线包的更新和下载
mPaaS客户端框架对离线包的下载行为作了深度的封装,下载过程如下:
(1) 如图1-6所示,客户端向MDS服务端发送请求,请求中提供了下载目标H5 App的ID;
图1‑6 离线包请求包信息
(2) 如图1-7所示,服务端返回该离线包的相关信息(如果存在);
图1‑7 离线包返回包信息
(3) 如图1-8所示,客户端根据返回信息中的Package URL并结合返回信息中的下载配置参数,主动去下载离线包的amr文件。
图1‑8 下载离线包
2)全量离线包的更新和下载
iOS和安卓平台均提供了API实现一次请求所有离线包的更新信息,其基本过程如下:
(1) 如图1-9所示,客户端向MDS服务端发送请求,请求中提供了本地已安装的H5 App的ID和本地版本号,外加一个特殊的App ID:nebula-*-all;
图1‑9 全量更新离线包
(2) 如图1-10所示,服务端返回所有符合条件的离线包信息(不在客户端版本范围内的,不返回);
图1‑10 全量更新离线包
(3) 如图1-11所示,客户端根据返回信息中的内容,主动去下载全量或增量的amr文件。
图1‑11 全量下载离线包
3)离线失败-fallback到线上
在某些情况下(例如,离线包本地验签失败),H5容器无法从本地获取所需的资源,客户端会转而从线上地址获取这些资源,如图1-12所示。
图1‑12 离线包请求fallback
7.问题排查举例
1)离线包无法更新
(1) 问题现象。
开发者通过MDS(实时发布服务)发布了一个新的H5应用离线包或一个新的小程序包,而客户端打开H5应用/小程序时,依然是旧版内容,不符合预期。
(2) 问题排查。
①发布状态检查:如图1-13所示,首先需要确认目标离线包的版本在发布状态中,如果不在发布状态中,请点击创建发布任务。
图1‑13 MDS配置检查
发布版本检查:
如果发布状态正常,则检查发布任务覆盖的客户端版本范围:对目标离线包版本点击查看,查看详细信息,如图1-14所示。其中客户端版本范围中的版本号指基于mPaaS框架的iOS/Android原生应用的版本号。特别的,iOS客户端的版本号值并不是Xcode项目的版本号,而是info.plist中Production Version字段的值。Android客户端的版本号值是build.gradle中versionName字段的值。
图1‑14 MDS版本配置检查
客户端配置检查:
mPaaS iOS/Android客户端开发框架都提供了离线包主动更新的API接口。正常情况下,每次打开离线包,框架自身也会主动检查是否存在更新。请确认mPaaS框架和H5容器/离线包组件接入是否正确,API使用是否正确。如果调用了主动更新API,请确认调用时机,排查requestAllNebulaApp(iOS)/updataAll(Android)是否被正确调用到。检查获取更新的RPC请求返回是否正常。在控制台中查看update api调用是发出的RPC请求返回是否正确。
通过抓包排查:
在离线包更新的问题上,如果开发者对排查方向不是非常明确,建议抓取HTTP包,根据HTTP包中的行为来分析排查更新问题。
如图1-15所示,通过抓包查看离线包更新信息请求体中的客户端版本号,确认是否在离线包发布客户端版本范围内。
图1‑15 版本配置抓包检查
如图1-16所示,查看离线包更新信息请求体中是否带有目标离线包的App ID或带有nebula-*-all字段。
图1‑16 服务端请求参数抓包检查
确认完请求参数后,在检查返回参数。如图1-17所示,确认离线包更新信息请求的返回数据中是否包含目标离线包及相关信息(amr地址,fallback地址等)。
图1‑17 服务端返回参数抓包检查
确认完返回参数后,在确认amr文件下载过程是否正常,如图1-18所示。
图1‑18 离线包下载抓包检查
2)离线包加载失败
(1) 问题现象
打开H5应用的时候,容器展示错误页面“系统繁忙,请稍后再试”,如图1-19所示。
图1‑19 离线包加载失败错误页面
(2) 排查过程
检查控制台输出日志,确认是否存在 RPC 7000 系列错误,如下所示,报错7001,7001表示签名校验失败。一般情况是无线保镖配置错误,重新配置无线保镖验证是否恢复。
2022-03-10 10:51:41.883119+0800 Demo[4765:231933] alipay.client.getUnionResource resp:{
"Content-Length" = 0;
Date = "Tue, 10 Mar 2022 02:51:41 GMT";
"Strict-Transport-Security" = "max-age=31536000";
"result-memo" = "%E9%AA%8C%E7%AD%BE%E7%9A%84%E5%8F%82%E6%95%B0%E4%B8%8D%E5%A4%9F%E3%80%82";
"result-status" = 7001;
"result-tips" = "%E7%AD%BE%E5%90%8D%E9%AA%8C%E8%AF%81%E5%A4%B1%E8%B4%A5%E3%80%82";
}