列表动态化配置方案介绍
导读
动态item方案是车货匹配业务组集体出品,用于快速实现组合布局的框架模型,已在 Android & iOS版 配货大厅、搜货列表、货源推荐等场景使用。 通过动态item配置,可以少发版甚至免发版支撑货源列表相关业务需求。
背景
1.业务支持
搜货相关的业务一直很频繁,各货源路线的规则也不尽相同。 客户端有着频繁发版、业务需求研发响应慢的困扰。
诉求:希望能少发版或不发版支持搜货列表相关的业务。
2.安全
货源列表遭遇爬虫。 对异常用户,客户端需要对若干敏感字段做脱敏展示,比如部分文字内容改成**。 后端接口修改相应数据内容,在客户端上展示效果不太理想。
诉求:希望客户端货源列表的卡片可以由服务端比较方便的控制样式。
3.代码优化
APP随着多年迭代演化,代码量越积越多,带来了可读性、可维护性上的问题。 比如,货源列表的相关页面场景有9个,相应的卡片有17种,车货匹配模块代码量5万行。
诉求:卡片收归。
着手解决问题
其他厂家类似问题如何解决
范围:iOS & 安卓。 美团,自定义native组件 天猫,自定义native组件
我们的痛点
1.业务场景较多,需要能快速支持列表样式修改调整 2.列表是核心业务,需要高性能、高稳定性
设计方案
范围:iOS & 安卓。
技术方案对比
作为业务团队我们从业务的角度审视技术方案。 带界面的业务基本分三种:
- 临时性业务——比如活动,几张页面生命周期可能2周,1周,甚至一两天。数量多,需求频繁,有可沉淀的东西,但变化更多。对极致性能不敏感。
- 常规业务——比如搜货列表,生命周期长,需要长期维护。数量有限,需求稳定,沉淀性好。对极致性能相当敏感。
- 基础业务——跟常规业务相比需求稳定性更高,对性能和稳定性有极高的要求。
对于第1种,我们认为未来一定属于HTML,随着WebView性能的提升和Mobile开发框架与开发技能日趋成熟,现阶段HTML体现出的劣势终将荡然无存。
Dynative
(如RN):虽然性能能满足,但由于该技术稳定性不够,且开发难度相对较大,所以对于常规业务还是非常谨慎的使用。
选择技术方案
结合我们团队所负责的业务形态,由于使用场景在搜货列表,对性能的要求比较高。
在性能、稳定性 & 开发周期 取得较好的平衡是我们的目标。
综合考虑后,我们决定使用组件化方案:native动态化组件方式,列表卡片支持动态可配置。
我们结合多年在业务上的经验制定了以粗粒度组件化+灵活布局容器
为基本理念的界面解决方案。
1、关于动态item配置框架
框架内置基础组件(文本,图片,Button等),以JSON为模板描述页面。Dynative方案兼具HTML方案的动态性和Native方案的高性能。
整体上,DynamicTemplateCell
作为根节点,复用tableview的能力;
卡片的子节点为布局容器DynamicRowView
,横行为主,其他控件浮动,每行一个容器,向下单行排列;
布局容器中按照各自的布局规则,在其内对任意组件进行排列。
2、关于动态item的样式
样式描述,我们引入了模板
。
通过配置下发的模板和搜货列表接口配合描述卡片的样式。
模板的意义
- 模板数据量较大,且改动不频繁,通过配置下发减少列表接口报文数据量
- 模板可将每行的元素确定,避免小组件移除添加过程中引起的性能损耗,提升手机帧率
- 模板key可以作为卡片重用的标识
至此,动态item的基础模型已经确定,放弃了第1种和第3种,重点关注第2种。从改造搜索列表的实现方案开始,通过几个月的时间证明这套模型和方案在业务上完全可行。进一步对方案进行抽象,并且开始周边建设。
动态item关注的重点
三个重点:面向业务、多端一致性和高性能。
面向业务
正如第一部分所讲的,动态item来源于多次试错和方向的调整,最终站在业务角度出发,权衡多项技术指标的结果。所以面向业务是出发点,是整个动态item体系的最基本原则。
基于这个原则,在端上动态item始终坚持粗粒度组件。 粗粒度意味着通用性和灵活性的下降,某种程度上还会对动态性造成影响,但在第2种业务中通用性、灵活性和动态性的需求是有节制的,在粗粒度上完全可以满足业务需求。 而且,粗粒度还会带给我们使用成本低,性能更好等优势。在 端上重点精力则投入到提升组件库复用度,布局容器和组件的丰富性,从而推动业务发展。
除了端上的工作,另一部分重点工作在控制台和服务网关的建设上。 作为一个面向业务的方案,控制台是业务方和产品的接口,控制台的主要目标是让业务方可以直接控制基于动态item建设的产品——调整页面布局,切换页面数据,等。 服务网关的建设目标是最大程度的降低业务创建动态item页面的压力和成本。
多端一致性
在多年的业务开发经历中,我们屡次被多端表现不一致的问题困扰。 为了实现业务诉求,不得不通过复杂的网关逻辑来兼容多端逻辑不一致情况,以实现表现一致。因此我们早早的制定了两个native端开发原则:
- 任意新功能的提出都是不区分平台,在功能设计中必须同时考虑多端功能,具体的实现方案和逻辑必须多端统一Review以保证多端表现一致。
- 任意一端的变更都必须在改动前把方案同步给其他端,而且变更必须多端同步发布。
高性能
在面向业务的原则之下,已经给高性能打下了一个良好的基础。而在高性能的思考上我们重点基于页面渲染效率和组件回收复用两方面。
- 页面渲染——为了提升渲染效率,动态item将在视图渲染之前把大量的计算工作在VM中完成,并缓存在VM组成的树形结构里。
- 回收和复用——动态item在Android和iOS平台上通过协议
DynamicWidgetProtocol
抽象描述出各个组件,通过key、value方式完成发现、赋值步骤。
动态化配置方案现状
具备的能力
1、跨平台支持 已有Android&iOS支持,一份数据,多端渲染一致
2、面向业务 流式布局,吸顶,浮标,内置布局可适应大多数场景,开放的样式规范,易于拓展卡片的布局
3、高性能 高效的回收复用算法,可定制化的粗颗粒度组件,适应复杂布局的场景,为丝滑般顺畅提供基础
4、动态组件
通过虚拟行
概念,支持自定义 JSON 动态创建组件视图
5、控制台 配套的后端服务设施,灵活构建 动态item 业务所需的数据,即所谓的模板。
名词解释,什么是组件
1、定义:最小单位的UI元素 日常使用的普通的View,如文本、按钮、图片等等 2、作用:负责UI元素展示 & 业务逻辑 组成元素:视图模型(ViewModel) & 样式(Style) 3、组件的基本样式,主要包括:组件背景、外边距、内边距、组件的宽高比等等,细节较多,这里不做展开。
结构
支撑的业务场景
1.支持最简单的逐行排列
如图所示,每一行支持多个元素横向排列,在横向排列的过程中,可以支持全部靠左对齐,又或者最后一个元素靠右对齐。 另外每一行之间,可以设置行与行的间距。 同时每一行也支持左边和右边的指定缩进大小。
2、支持在逐行排列的基础上,加入额外一些可以指定相对位置的元素
如上图,头像就是一个额外的相对位置元素,脱离了逐行布局,他可以: 设置自己的位置,这些可设置的位置包括左上、左中、左下、右上、右中、右下。同时在每一个相对的位置,还可以设置上下左右的偏移量。
又比如: 其中,电话按钮,也是一个可以指定相对位置的元素,同样脱离了逐行布局。
3.支持在逐行排列的基础上,加入额外一些可以指定相对位置的元素集合
这个与2中的区别是,2中的相对位置是一个元素,而这里可以加入一个元素集合,元素集合相对于一个元素而言,他可以设置: 这个元素集合里面,各个元素的相对位置,这些相对位置包括:整体靠左对齐、整体靠右对齐、整体居中对齐。 如下图:
其中,红色箭头的就是2中所述的相对位置元素,而蓝色箭头就是3中要说明的相对位置元素集合。相对位置元素集合的意思, 就是这一块相对位置中,可能包括多个元素,故称之为元素集合。
使用示例
普通货源使用示例
模板配置示例
低端机性能
iOS
Android
未来计划
1、随着几个月的实际应用,模板的数量在增多,需要升级后台模板管理工具,减少模板维护成本
2、需要支持的更多列表界面,进而完成卡片收归,代码优化
3、模板可视化工具优化,在管理后台,实现所见即所得
4、服务端相关优化
4.1. 保证模板的配置下发和列表数据下发同步
4.2. 目前模板已经支持了根据灰度、版本、操作系统的下发,但推送的列表数据还是一个整体的集合,这个有进一步优化的空间,可以减少数据下发流量。