美团开源Graver框架:用“雕刻”诠释iOS端UI界面的高效渲染

Graver 是一款高效的 UI 渲染框架,它以更低的资源消耗来构建十分流畅的 UI 界面。Graver 首创性的采用了基于绘制的视觉元素分解方式来构建界面,得益于此,该框架能让 UI 渲染过程变得更加简单、灵活。目前,该框架已经在美团 App 的外卖频道、独立外卖 App 核心业务场景的大多数业务中进行了应用,同时也获得美团外卖内部技术团队的承认和确定。html

App 渲染性能优化是一个广泛存在的问题,为了惠及更多的前端开发同窗,美团外卖 iOS 开发团队将其进行开源,Github 项目地址与使用文档详见:https://github.com/Meituan-Dianping/Graver 。咱们但愿该框架可以应用到更广阔的业务场景。固然,咱们也知道该框架尚有待完善之处,也但愿能与更多技术同行一块儿交流、探讨、共建。前端

前言

咱们为何须要关注界面的渲染性能?App 使用体验主要包含产品功能、交互视觉、前端性能,而使用体验的好与坏,直接影响用户持续使用仍是转而使用其余 App,因此咱们很是关注 App 的渲染性能。并且在互联网产品流量竞争愈发激烈的大背景下,优质的使用体验能够为现有用户提供更好的服务,进而提升用户转化和留存,这也意味着创收、盈利。git

背景

美团外卖 App 从2013年成立至今,已经走过了五个春秋,在技术层面前后经历了快速验证、模块化、精细化和平台化四个阶段,产品形态上也日趋成熟。在此期间,咱们构建并完善了监控、报警、容灾、备份等各项基础设施,Metrics 便是其中的性能监控系统。github

曾经一段时间,咱们之外卖 App 首页商家卡片列表为例,经过 Metrics 性能监控系统发现其在 FPS、CPU、Memory 等方面的各项指标并不理想。因而,经过 Xcode 自带的 TimeProfile 等性能检测工具,而后结合代码分析等手段找到了现存性能瓶颈。与此同时,咱们梳理其近半年的迭代版本需求发现,UI 每每须要根据不一样场景甚至不一样用户展现不一样的内容。为了避免断迎合用户的需求,快速应对市场变化,这种特征还会持续存在。然而,它会带来如下问题:编程

  • 视图层级越发复杂、视图数量越发众多,从版本长期迭代来看是潜在的性能瓶颈点。
  • 如何快速、高效支撑 UI 变化,同时保证不会二次引入性能瓶颈。

Graver 介绍

为了解决现存的性能瓶颈以及后续潜在的性能瓶颈,咱们指望构建一套解决方案,该方案能在充分知足外卖业务特征的前提下,以标准化、一站式的方式解决 iOS 端 App 的渲染性能问题,而且对研发效率有必定提高, Graver(雕工)框架应运而生。后端

由于 Graver 首创性地采用了全新的视觉元素分解思路,因此该框架使用起来十分灵活、简单。咱们先来看一下 Graver 的主要特色:缓存

性能表现优异安全

之外卖 App 首页商家列表为例,应用 Graver 以后5分位滚动帧率从满帧的<font color=red size = 2>84%</font>提高至<font color=red size = 2>96%</font>,50分位几乎满帧;CPU 占用率降低了近<font color=red size = 2>6个百分点</font>,有效提高了空闲 CPU 的资源利用率,下降了峰值 CPU 的占用率。如图3所示:性能优化

“一站式”异步化网络

Graver 从文本计算、样式排版渲染、图片解码,再到绘制,实现了全程异步化,而且是线程安全的。使用 Graver 能够一站式得到所有性能优化点,可让咱们:

  • 再也不担忧散点式的“碰见一处改一处”的麻烦。
  • 再也不担忧离屏渲染等各类可能致使性能瓶颈的问题,以及使人头痛的解决办法。
  • 再也不担忧优化会有遗漏、优化不到位。
  • 再也不担忧将来变化可能带来的任何性能瓶颈。

性能消耗的“边际成本”几乎为零

Graver 渲染整个过程除画板视图外彻底没有使用 UIKit 控件,最终产出的结果是一张位图(Bitmap),视图层级、数量大幅下降。之外卖 App 首页铂金展位视图为例,原有方案由58个控件、12层级拼接而成;而应用 Graver 后仅需1个视图、1级层级绘制而成。 伴随着需求迭代、视觉元素变化,性能消耗恒属常数级。如图4所示:

渲染速度快

Graver 并发进行多个画板视图的渲染、显示工做。得益于图文混排技术的应用,达到了内存占用低,渲染速度快的效果。因为排版数据是不变的,因此内部会进行缓存、复用,这又进一步促进了总体渲染效率。Graver 既作到了高效渲染,又保证了低时延页面加载。

以“少”胜“繁”

Graver 从新抽象封装 CoreText、CoreGraphic 等系统基础能力,经过少许系统标准图形绘制接口便可实现复杂界面展现。

基于位图(Bitmap)的轻量事件交互系统

如上述所说,界面展现从传统的视图树转变为一张位图,而位图不能响应、区份内部具体位置的点击事件。Graver 提供了基于位图的轻量事件交互系统,能够准确识别点击位置发生在位图的哪一块“绘制单元”内。该“绘制单元”能够理解为与咱们一向使用的某个具体 UI 控件相对应的视觉展现。使用 Graver 为某一视觉展现添加事件如同使用系统 UIButton 添加事件同样简单。

全新的视觉元素分解思路

Graver 一改界面编程思路,与传统的经过控件“拼接”、“添加”,视图排列组合方式构建界面不一样,它提供了灵活、便捷的接口让咱们以“视觉所见”的方式构建界面。这一特色在下文Graver使用中详细阐述,正是由于该特色实现了研发效率的提高。

Graver 使用

Graver 引入了全新的视觉元素分解的思路。借助该思路能够实现经过一种对象来表达任一视觉元素、甚至是任一视觉元素的组合,从而消除界面布局的复杂性。

咱们先来回顾下传统界面的构建方式,之外卖 App 商家卡片其中一种样式为例,如图6所示:

在实现商家卡片的界面样式时,一般会根据视觉上的识别、交互要求来创建界面展现与系统提供的 UI 控件间的映射关系。以标号②位置的样式为例,在考虑复用的状况下一般这部分会使用三个系统控件来完成,分别是左侧蓝底的“预订”使用 UILabel 控件、右侧的蓝色边框“2.26.21:30起送”使用 UILabel 控件、把左右两侧 UILabel 控件装起来的 UIView 控件;在肯定好采用的 UI 控件以后,须要针对展现样式分门别类的设置各个控件的渲染属性来实现图示 UI 效果,渲染属性一般一部分预设,一部分根据业务数据的不一样再进行二次设置;其次,设置各个控件的内容属性实现业务数据内容的展现,展现的内容通常是网络业务数据经逻辑处理、加工后的数据。若是涉及到点击事件,还须要添加手势或者更换成 UIButton 控件。接下来,须要根据视觉要求实现排版逻辑,以标号⑧、⑨为例,当标号⑧位置的数据没有的状况下,须要上提标号⑨位置的“美团专送”到图示标号⑧位置。诸如相似的排版逻辑随处可见。对于图示任一位置的展现内容都存在上述的循环思考、编写工做。随着界面元素的增长、变化,问题会变得更加复杂。

传统的界面构建方式实际上是在 UI控件的维度去分解视觉元素,具体是作如下四方面的编写工做:

  • 控件选择:根据展现内容、样式、交互要求肯定采用哪一种系统控件。
  • 布局信息:UI 控件的大小、位置,即 Frame。
  • 内容信息:UI 控件展现出来的业务数据,如标号(1)位置的“星巴克咖啡店”。
  • 渲染信息:UI 控件展现出来的效果,如字体、字号、透明度、边框、颜色等。

最后,将各个控件以排列组合方式合成为一棵视图树。

Graver 框架提供了以画板视图为基础,经过对更底层的 CoreText、CoreGraphic 框架封装,以更贴近“视觉所见”的角度定义了全新视觉元素分解、界面展现构建的过程。

一般“视觉所见”可划分为两部分:静态展现、动态展现。静态展现包含图片、文本;动态展现包含视频、动画等。在视觉展现所有为静态内容的时候,一个 Cell 便是一个画布,除此之外没有任何 UI 控件;不然,能够按需灵活的进行画布拆分来知足动画、视频等须要。

以图6商家卡片中标号②、⑧为例,新实现方式的伪代码是这样的:

WMMutableAttributedItem *item = [[WMMutableAttributedItem alloc] init];
[[[[item appendImage:[[UIImage wmg_imageWithColor:"blue"] wmg_drawText:"预订"]] 
         appendImage:[[UIImage wmg_imageWithColor:"clear" borderWidth:1 borderColor:"blue"] wmg_drawText:"2.26.21:30起送"] 
         appendWhiteSpaceWithWidth:"width"]//整体宽度减去②和⑧的宽度总和剩余部分
         apendText:"50分钟|2.5km"];

上述实现方式便是把标号②、⑧部分做为一个总体来实现,任何单一系统控件都没法作到这一点。

Graver 渲染原理

如图8所示,Graver 涉及多个队列间的交互,之外卖 App 商家列表为例,总体流程以下:

  • 主线程构建请求参数,建立请求任务并放入网络线程队列中,发起网络请求。
  • 网络线程向后端服务发起请求,得到对应的业务模型数据(如包含了店铺名称,商家头图,评分,配送时长,客单价,优惠活动等店铺属性的商家卡片列表)。
  • 网络线程建立包含业务模型数据(如商家卡片列表)的排版任务,提交到预排版线程处理,进入预排版流程。预排版队列取出排版任务,交由布局引擎计算 UI 布局,将业务模型解析成可被渲染引擎直接处理的,包含布局、层级、渲染信息的排版模型。解析结束后,通知主线程排版完成。
  • 主线程获取排版模型后,随即触发内容显示。根据相对屏幕位置及出现的前后顺序,建立包含将须要显示区域信息的绘制任务,放入异步绘制线程队列中,发起绘制流程。
  • 异步绘制线程队列取出绘制任务,进行图文绘制,最终输出一张包含了图文内容(如商家卡片)的图片。绘制任务结束后,通知主线程队绘制完成,主线程随后展现绘制区域。

总体按照队列间串行、队列内并行的方式执行。

业务应用

Graver 在外卖内部发布以后,咱们也将其推广到更多的业务线,并但愿 Graver 可以成为对业务开展有重要保障的一项基础服务。通过半年多的内部试用,Graver 的可靠性、渲染性能、业务适应能力也受到外卖内部的确定和承认。截止发稿时,Graver 已经基本覆盖了美团 App 的外卖频道、独立外卖 App 核心业务场景的大多数业务。下面列举 Graver 在外卖业务的部分应用案例:

经验总结

总结一下,对于界面渲染性能优化而言,要站在一个更高角度来思考问题的解决方案。横向上,从普适性角度解决性能瓶颈点,避免其余人遇到相似问题的重复工做;纵向上,从长远考虑问题作到防微杜渐,一次优化,长期受益。基于此,咱们提出一站式、标准化的渲染性能解决方案。诚然,这会遇到不少难点。面对界面样式构建的问题,系统 UIKit 框架着实为咱们提供了便利,然而有时候咱们须要跳出固有思惟,尝试创建一套全新界面构建、视觉元素分解的思路。

参考资料

前端感官性能的衡量和优化实践

做者简介

洋洋,美团高级工程师。2018年加入美团,目前负责【美团外卖】和【美团外卖频道】的 iOS 客户端首页业务,以及支撑首页业务的技术架构、工具和系统的开发和维护工做。

招聘

美团外卖长期招聘 Android、iOS、FE 高级/资深工程师和技术专家,Base 北京、上海、成都,欢迎有兴趣的同窗投递简历到chenhang03#meituan.com。

相关文章
相关标签/搜索