作者:逍菲、崖松、子伦
饿了么端 618、国庆、双 11、双 12 等大促会场基本上会标配底部导航,在之前一般 H5 容器中底部导航是前端实现,每次点击会场底部导航的 tab,都会重新启动一个流动页面笼罩在下面,即便之前关上过的 tab 也都要从新创立和加载,体验不佳,且 H5 也不能很好的联合 Native 能力做进一步的体验和性能优化。
通过调研发现手淘 PHA 框架可解决上述痛点问题,PHA 容器底部 TabBar 为 Native 渲染,tab 点击时底部 bar 不会重建,tab 对应的 webview 在整个 PHA 容器中也能够平滑过渡、无缝切换,无需另起容器。且加载过的 tab 流动页面 Webview 会常驻内存,当再次拜访时会间接切换至前台,更靠近 native 体验。
在去年 618、国庆、双 11 和双 12 大促中,联合饿了么业务个性又陆续落地了一些特色优化伎俩,带来了更好的性能体验和业务成绩。
双十一上线成果
成果视频查看请点击:饿了么双十一 PHA 会场实际
老容器和 pha 容器比照。其中左侧为老容器会场,右侧为 pha 容器会场。
PHA 简介
什么是 PHA,PHA 全称 Progressive Hybrid App,是晋升 Hybrid 体验的一种新框架,提供了一些 Native 同层组件以及渐进式加强策略来创立 Hybrid APP 利用,让这些利用具备与 Native 雷同的用户体验。
- PHA 应用了 Web Application Manifest 的配置并且对配置进行了性能扩大
- 每个 PHA 利用都会启动一个 App Worker,Worker 是独立于以后页面运行在客户端里的一段 JS 脚本。可在 Worker 中定制业务逻辑,如基于 LBS 申请底部 Tab 展现的数据列表
- 利用下能够有多个页面,每个页面的默认渲染引擎是 WebView
- 每个页面中 PHA 提供了像下拉刷新、页头等 UI 能力,都能够通过在 Manifest 中定制
- 针对利用 PHA 还提供了 Tab 容器、Swiper 容器、启动屏等 UI 能力和预申请、离线缓存等性能优化能力,可通过在 Manifest 中配置实现
pha 架构图
饿了么接入计划
本地生存跟淘宝等业务次要的区别为前者强依赖 LBS 属性,包含底部 Tab、商品、品牌等数据的召回。因而须要在用户关上 PHA 框架时,执行定位并加载对应的底部 Tab、顶部横滑数据后,动静组装出对应的 manifest.json 数据来渲染 PHA,整体架构图如下:
架构图
B 端链路
墨斗平台依赖天马源码页面服务来创立会场框架,沿用墨斗数据搭建来配置底部 Tab 和 顶部 Swiper 的数据,实现定投,次要流程如下:
注:“墨斗”是一个模块搭建平台,“天马”能够提供根底搭建服务。
数据搭建
数据搭建是墨斗中提供的数据多排期定投能力,配置定投并公布后可失去以后配置的惟一资源位 ID,业务可通过异步接口取得配置数据。
会场框架工具
新增会场框架工具,工具提供了会场框架创立、公布及编辑能力,创立并公布框架后即可失去框架投放链接。
C 端链路
C 端链路由客户端联合前端实现,次要蕴含以下 3 局部:
1、客户端 PHA 框架:集成了 Tabs 容器、Swiper 容器、启动屏、Appworker、预加载等框架外围能力
2、源码模版页:作为 PHA 框架的入口,同时提供 PHA 失常加载入口 (native.xtpl) 和降级入口 (web.xtpl)
3、AppWorker 服务:能在框架渲染前有机会依据业务诉求定制 manifest,包含头部横滑容器的 UI 定制,事件处理、埋点等
整体加载链路图
客户端接入革新
路由层
革新饿了么路由层,减少 pha 入口,并在入口处减少 native 的降级策略、灰度管制等逻辑。
适配器:native 导航头适配
因为剥离了手淘的 ui 库,饿了么须要自行实现导航栏的: 显示、暗藏、各类主题、滚动变色、title 设置、logo 设置、事件回调、降级跳转等,此外双端也提供了一些导航头、状态栏等公有 jsapi 供前端进行调用。
iOS 端通过 PHANavigationBarProtocol 实现对应办法,Android 端以零碎 Toolbar 为根底,定制饿了么的 TranslucentToolbar,以 Fragment 的模式嵌入到 PHA 容器 Activity 中。
下图是 native 端导航头,title 反对设置文字、加载图片,导航栏主题反对通明、红色:
文字 & 图片导航栏
下图是 light 和 dark 格调的状态栏:
light&dark 状态栏
适配器:图片加载适配
饿了么 iOS 端因为本人保护了图片库,须要对图片加载进行适配,实现 PHAImageLoaderProtocol 及其图片加载相干办法。
淘系依赖剥离
饿了么对于包大小有严格的管制,对于新引入的二三方库审核严格。饿了么端接入 pha 较早,晚期版本中存在额定的手淘依赖,且有些性能饿了么临时未用到,或已有相似的实现计划,因而须要对局部手淘依赖库进行剥离,对不须要的性能进行剪裁。
安卓剥离的间接依赖库约 20 个,如:直播库、公共资源库、ui 库、compat 库、启动框架库、atlas 等,总大小约:7.2M+,波及文件改变个数:100+
注:目前安卓最新的官网 2.0 版本已剥离了这些依赖,大大的赞!iOS 端在一接入 pha 时依赖已根本剥离,无需大的革新。
前端接入革新
框架服务
1、源码模版:作为 PHA 框架的入口,同时提供 PHA 失常加载入口 (native.xtpl) 和降级入口 (web.xtpl)
- 失常入口:基于平台创立会场框架时录入的数据生成 manifest 半成品,后果中蕴含 AppWorker 地址,创立框架时的配置信息等,客户端执行 AppWorker 文件后,启动 PHA 框架渲染
- 降级入口:为不反对 PHA 的低版本或 PHA 创立失败时提供对立的降级解决,用一般 H5 容器关上投放链接中的 downgradeUrl 地址实现降级,保障业务可用
2、AppWorker 服务:能在框架渲染前有机会依据业务诉求定制 manifest,次要提供如下能力
- 定位、申请底部 bar、顶部 swiper 数据
- 头部横滑容器的 UI 定制、事件处理
- 和 PHA 的事件、音讯解决
- 构建最终的 manifest 文件
- 启动框架渲染
- 埋点等
会场链路
1、页面 solution、根底 util、componet 革新
2、多个模块革新
- 通明头模块:之前通明头是 H5 联合 Native 来实现的,业务定制能力绝对较弱,为了解决这个题,针对 PHA 容器实现了纯 H5 版的通明头模块
- 底部导航模块、搜寻模块、分享模块:兼容 PHA 和非 PHA 容器
埋点革新
PHA 框架提供一套埋点 API,客户端和前端需依据本人的埋点计划进行适配革新,统计和上报口径跟非 PHA 下会场埋点保持一致,次要有以下两点:
- 需在每次切换页面时上报 PV,包含曾经浏览过的页面,如 Tab A 切到 Tab B 再切到 Tab A 时,在最初的 Tab A 页面须要触发 PV 上报
- 底部 Tab 或顶部 Swiper 容器切换不同 Item 时上报点击埋点
性能优化
饿了么端 pha 容器加载流程次要为下图四个阶段,针对不同阶段可进行对应的性能优化伎俩。
- pha 容器阶段:半成品 manifest 和 worker 可进行预取或缓存优化;残缺 manifest 数据申请组装阶段可进行经纬度的预取和接口的预申请;
- webview 阶段:webview 可进行预初始化,主文档加载能够用模版化形式进行优化;
- 业务阶段:针对业务 js、css 资源可进行资源离线和缓存,对罕用 js 资源可进行内置;对业务接口数据可进行预申请;预热和预渲染。
官网 PHA 框架优化伎俩
pha 框架自身提供了 manifest 预申请和缓存、html 模板化、离线资源存取、内置 Js 预渲染等优化伎俩。
以 iOS 端双十一会场为例,应用 manifest 和 worker 预取,优化容器创立工夫 200ms 以上。
饿了么端特色性能优化
PHA webview 预热
关上 pha 首屏页面和切换 tab 时须要执行容器创立和主文档加载,有较长时间的白屏,体验不佳。预渲染页面无疑是性能成果最佳伎俩,但一方面会造成资源节约,另一方面也会带来很大的内存压力,不能随便滥用,后续若能和端智能更好联合或者能力更好的施展它的价值。
饿了么端对首屏外的 tab 采纳了预热计划(预热页面最大个数可配置),来打消 tab 切换时的白屏工夫。预热和预渲染的不同点为:预热在离屏阶段拿到主文档后不发动首屏接口申请。在首屏页面渲染实现后,将剩下的底部和顶部 item 对应的 webview 都预热并缓存好,当用户点击对应 tab 时再生产 webview 进行上屏操作,具体实现复用 pha/preload 子模块链路并进行了一些革新,参考了 TSchedule 的预渲染逻辑。次要流程如下图所示:
优化前后链路比照:
上面具体展现预热成果(左侧为未开启预热,右侧为开启预热状态):
成果视频请点击查看:饿了么双十一 PHA 会场实际
业务接口预加载
会场页面的首屏接口耗时较长,局部甚至达 2s 以上,为了缩短页面加载耗时,对首屏接口进行预申请。思考到饿了么端之前已通过 TSchedule 反对了接口预申请的能力和包大小问题,因而决定不引入 pha 的 prefetch 模块,而是借助饿了么现有能力对 pha 进行 data prefetch 的适配化革新。
由客户端同学提前公布 orange(开关配置公布平台)预申请配置,pha 会场在首屏路由、底部 tab 切换、顶部 pageheader 切换时提前触发接口预申请,也提供 jsapi 供前端自行调用预申请,优化成果显著,目前曾经是饿了么端会场业务必备优化项。
(1)、首屏 webview 加载前网络数据异步预申请
(2)、启动前路由阶段网络数据异步预申请
(3)、tab 切换 webview 加载前网络数据异步预申请
(4)、通过 jsbridge 在 webview 加载前网络数据异步预申请
残缺 manifest 数据申请优化
本地生存业务多对定位有强依赖,对于会场业务目前只能先返回半成品 manifest 文件,在 worker 中调用端上 jsapi 拿到经纬度后发动接口申请,获取残缺 manifest 相干数据进行组装;对于非会场的单页面业务进行接口申请时也大都须要经纬度信息。
经纬度预取
形式一: 将经纬度信息注入半成品 manifest(针对须要 pha worker 对半成品 manifest 文件进行解决的业务场景)
在回传给前端的 manifest 半成品 json 中,追加上首页缓存的经纬度数据,省去一次 jsbridge 调用耗时。优化前后流程对比方下图所示:
追加的经纬度信息模板:
形式二: 在入口链接处传入经纬度(针对无需 pha worker 的场景)
大多单页面业务在一开始就能获取到残缺的 manifest 数据,不须要 worker 进行额定解决,也就无奈间接通过形式一取得注入的经纬度信息,因而咱们采纳了另一个计划,给 pha 入口链接(manifest url)拼接经纬度参数,并通过 pha 参数透传的能力将其拼接到 H5 内页的链接上。具体流程如下:
残缺 manifest 数据接口预申请
在 worker 获取经纬度后,会应用页面 id、资源 id 和经纬度发动一个接口申请,获取残缺 manifest 所需数据(pages、tab 等),数据返回后拼接成残缺 manifest 数据,而后调用 jsapi 告诉端上更新 manifest,进行 tab 和页面的加载,此接口耗时大略 200ms 左右。
通过在路由阶段预申请此接口来进行优化,因为接口所需的页面 id 和资源 id 针对同一大促会场投放期间根本不会扭转,因而提前公布的预加载配置将这两个 id 间接设为固定值,而经纬度在预申请发动时动静获取。
此性能上线之后通过两个版本的比照,首屏耗时整体缩小约 150ms。
稳定性
降级
PHA 框架渲染前的任何一步出错可能导致框架初始化失败,为实现同一个链接投放到饿了么新老版本,并保障业务在各种异样场景下可用,需做到无缝降级到 H5 容器,流程如下:
预案
在整个双十一大促开始前,针对 pha 会场可能呈现的各种异常情况进行了预案的录入和演练,例如:会场降级,预热敞开、接口预加载敞开、manifest 预取敞开等,在平安团队和测试团队同学的独特反对保障下,pha 容器会场在大促期间运行稳固,未呈现任何重大故障。
监控和报表
在 dp2 监控平台构建了 manifest 命中率监控、离线资源命中率监控、降级监控、性能监控、预热命中率监控、首屏耗时监控、容器内 webview 加载耗时监控、白屏监控等相干报表。
此外手淘目前在建设容器大盘,ios 端曾经初步进行了接入,期待大盘后续例如告警,二方业务数据展现等建设。
总结和瞻望
通过 pha 框架的接入及一系列的优化伎俩,双端优化首屏耗时缩小 650ms 左右,打消了切换 tab 时的白屏工夫,晋升了饿了么端大促会场的用户体验,同时也促成了业务数据的晋升。
据经营侧数据统计,去年双十一主会场底部导航 Tab 的曝光点击率,相比国庆大促正式期晋升超过 50%。自 618 大促正式期试点 PHA 以来,新底部导航点击率持续上升。
后续前端需解决拼链接的问题作为常态化的产品能力反对各业务场景应用,端侧也将进一步摸索其余的优化计划,比方: Tabbar 直出渲染、pha 容器 Fragment 化、quickjs 引入等。此外除会场业务,饿了么端超会局部业务也进行了 pha 投放,获得了一些性能上的收益。
冀望将来饿了么所做的优化点能给大家一些启发与思考,服务更多适合业务,进一步晋升用户体验。
关注【阿里巴巴挪动技术】微信公众号,每周 3 篇挪动技术实际 & 干货给你思考!