1. 背景

跨平台动态化技术是目前移动互联网领域的重点关注方向,它既能节约人力,又能实现业务快速上线的需求。经过十年的发展,美团App已经变成了一个承载众多业务的超级平台,众多的业务方对业务形态的快速迭代和更新提出了越来越高的要求。传统移动端”静态“的开发方式存在一系列问题,比如包体积增长过快、线上Bug修复困难、发版周期长等,已经不能满足高速发展的业务需要。因此,美团平台自研了一套跨平台动态化方案——MTFlexbox。

目前,MTFlexbox已经广泛应用于美团首页、搜索、外卖等多个业务场景,并且已稳定运行两年有余。在MTFlexbox规范下,只需要写一份布局文件,就可以适用多端。在实际开发中,客户端开发同学开发布局的同时也要添加好埋点信息,帮助产品同学来评估上线后的效果。但现有布局埋点存在成本过高、准确率较低等痛点,为了解决这些问题,我们充分了解数据组开发人员和产品对数据统计的诉求,结合对MTFlexbox原理的深入理解,围绕MTFlexbox的埋点上报做了很多持续、有针对性的自动化工作,帮助多个项目的效率得到了显著提升。本文主要介绍美团在MTFlexbox自动化埋点方向所进行的一些探索,希望对大家能够有所帮助。

2. MTFlexbox介绍

2.1 MTFlexbox原理

MTFlexbox是美团内部一套非常成熟的跨平台动态化解决方案,遵循了CSS3中提出的Flexbox规范,抹平了多平台的差异。MTFlexbox首先按照Flexbox的规范,定义了一套三端统一的XML布局文件,并将布局文件上传至后台;客户端下载带有布局文件的JSON数据后,解析布局并绑定JSON数据,最终交由Native渲染成视图。MTFlexbox的整体架构图如下所示:

MTFlexbox架构图

如果要用一句话来解释MTFlexbox的原理,就是按照约定的规则将XML内容映射成Native布局。从Android开发者的角度想,可以认为是把传统XML布局文件由内置改成从网络下发,实现展示样式动态改变的效果。上图第一层是MTFlexbox需要的输入,包括XML布局文件和展示的业务数据。其中XML布局文件中包括UI标签和埋点信息,每一种类型的埋点信息都作为一种属性和某一个UI标签相绑定。展示的业务数据可以通过后台下发或者写死在本地。为了将XML文件与具体的View进行解耦,MTFlexbox在XML与View之间增加了一层Node层,即先将XML解析成Node树,再将Node树解析成View树。MTFlexbox共有3层缓存:对XML文件的缓存、对Node节点的缓存、对View的缓存。其中缓存View指的是缓存一个XML创建的View,通常只会缓存rootView。在Node树生成了View树并绑定JSON数据后,才会最终渲染成Native控件。

2.2 MTFlexbox适用场景

MTFlexbox基本上支持Native上常用的基础控件的展示,对有UI定制化的需求支持度很高。但MTFlexbox的XML布局需要在运行前编写完成,只支持简单的三元表达式,逻辑能力有限。因此,MTFlexbox特别适合布局样式复杂、变动频繁但交互简单的业务场景。例如美团App首页、搜索结果页等。这些业务场景都具备以下两个特点:

面向多业务方:各业务方有自己的个性化丰富样式,且不同时期可能需要不同的样式。

交互简单:点击跳转完成流量输送的简单交互。

下面是MTFlexbox使用场景的一些截图:

2.3 MTFlexbox自动化埋点前期工作

在美团实际的业务场景中,卡片的点击、曝光和加载数据是分析一个新产品形态上线效果好坏的最基本方式之一。相对应的,客户端的数据采集方式是洞察对于模块的点击、曝光和加载事件,然后结合上下文环境,比如页面标识、模块标识等,最后使用埋点上报工具和业务字段一起进行上报。MTFlexbox作为模块级别的动态布局UI展示框架,对于数据采集方式的支持也是必不可少的。MTFlexbox针对数据采集的方式,做了以下两件事:

制定了一套双端统一的埋点标准化规范。

埋点类型定义成Tag标签属性,写入布局文件中。

MTFlexbox结合美团自研的客户端数据上报工具,定义了多个专门针对埋点的特有属性字段,主要类型如下:

客户端开发人员在编写布局文件时,可以根据具体的产品需求,对不同控件的标签添加埋点属性,并且写入需要上报的业务字段。这样可以达到与Native埋点相同的效果,并且双端只需要配置一份埋点。以see-mge4-report埋点为例,布局埋点代码如下:

<Container style="width:360pt;justify-content:center;" >
<Var name="see_MGE4" type="json">
{
"bid":"xxxxx",
"cid":"yyyyy",
"lab":{
"isDynamic":true,
"gather_index":"{extra.gather_index}",
"index":"{extra.index}"
}
}
</Var>
<Container
see-mge4-report="{see_MGE4}"
click-url="{business.iUrl}"
visibility="{{display.itemDynamic.imageUrl}?visible:displaynone}" > <Img style="width:331pt;height:106pt;justify-content:center;"
border-radius="5pt"
scale-type="center-crop"
src="{display.itemDynamic.imageUrl}"
background="#FFF8F8F8" />
</Container>
</Container>

2.4 MTFlexbox动态化研发流程

MTFlexbox动态化研发流程

从上述MTFlexbox动态化研发流程图中可以看出,数据需求和产品需求需要客户端开发人员在同一份布局文件中耦合在一起去实现,而且埋点属性和布局控件相绑定。这就导致在埋点过程中会出现很多问题,总结如下:

埋点成本过高

  • 沟通成本较高:对于一个新的产品需求,首先产品需要将埋点需求提给数据组,数据同学理解了产品需求后产出埋点文档;然后产品、数据同学、客户端开发同学三方进行需求评审和埋点评审,沟通埋点需要上报的字段和时机等细节。很多时候,一次沟通不到位,还需要反复沟通或者重新沟通,直到产品、数据同学和客户端开发人员三方对需求和埋点的理解一致为止。平均一个5PD(5PD指5个工作日)的需求需要消耗数据同学和客户端开发人员各1PD的时间来进行理解和沟通。

  • 开发成本过高:客户端开发人员在编写XML布局文件时,往往要花30%左右的时间进行手动埋点和自测校验。

埋点线上事故多

  • 因整个埋点缺乏自动化的埋点校验和预警机制,一旦开发人员出现人为的失误,导致错埋、漏埋现象,都有可能引发严重的线上故障。例如,客户端开发人员手动埋点时,出现人为失误引入了错误数据;产品验收阶段需要修改布局样式,客户端开发人员会出现”仅修改布局而遗漏埋点“的问题。

鉴于MTFlexbox存在埋点成本过高和线上问题较多的突出问题,我们迫切的希望通过一些手段来最大程度的规避和解决这类问题。埋点成本过高的原因在于MTFlexbox将布局和埋点耦合在一起编写,客户端开发人员需要做的事情过于”杂“和”多“。找到了这个痛点,很容易想到将埋点上报和布局编写解耦,让客户端开发人员只负责编写布局,数据同学只负责埋点配置,以此降低开发和沟通成本;同时通过自动化埋点校验手段提升埋点准确率,优化流程,减少线上事故的产生。基于此,产出我们理想的布局和埋点解耦之后的动态化研发流程,如下图所示:

新的动态化流程

3. 业内自动化埋点方案调研与参考

3.1 美团外卖前端无痕埋点实践

外卖团队在他们原有代码埋点方案的基础上,演化出了一套轻量的、声明式的前端埋点方案。详细内容可以参考博客:《美团点评前端无痕埋点实践》。此方案通过声明式埋点的方式实现了埋点代码与业务逻辑的解耦,并且支持对通用的业务数据的自动化上报。但此方案不能完全实现自动化埋点,并且实现成本较高。

3.2 Mixpanel

Mixpanel是一个已经商业化的可视化埋点方案,采用了截屏的方式在IDE中完成控件的圈选操作,体验较好值得我们借鉴。不过该方案主要面向非技术人员,不支持上报业务字段数据。

3.3 HubbleData

HubbleData是网易开发的一个洞察用户行为的数据分析系统,提供一套完整的数据解决方案。

网易对XPath做了优化,主要体现在View索引的计算上:

  • 原始XPath计算方式:每个ViewGroup下的所有View作为一个数组,索引从0开始。例如上图Button控件的XPath标识为:LinearLayout[0]/FrameLayout[0]/RelativeLayout[1]/Button[1]
  • 网易XPath计算方式:每个ViewGroup下的所有View先按控件类型分类,然后再把每个类型中的控件按照数组的方式,从0开始。例如上图Button控件的XPath标识为:LinearLayout[0]#rootView/FrameLayout[0]/RelativeLayout[0]#container/Button[0]#btn

但是网易的这次优化,并没有解决由于同类型控件位置变更而引发的埋点错误问题,根源在于控件唯一标识不够准确。同时网易的修改仅限控件的一些固有属性,并没有搜集到更有价值的业务数据。

结合上述四种方案的优缺点,自动化埋点需要具备的几个条件,即:简洁直接的流程、友好可视化的前端配置界面、业务字段的可配置化、埋点有效性的检测。我们的方案就是基于这几个目标而诞生的。

4. 我们的方案

整体流程

MTFlexbox自动化埋点的核心流程,分为以下五步:

  1. 客户端开发人员根据设计稿开发XML样式文件,自测通过后将XML样式文件与接口数据上传至MTFlexbox管理后台。
  2. MTFlexbox管理后台自动连接远程移动设备,并发送布局处理命令。远程移动设备将布局渲染结束后,抓取截图和布局层级信息(包括控件父子关系、控件位置、大小等信息)并上传至管理后台。
  3. 前端页面从后台拿到DPath路径信息、坐标信息和截图信息,提供一套可视化的界面供数据同学进行模块内任一控件的埋点圈选配置。数据同学根据自身的需求,从目录树中圈选出自己希望配置埋点的控件。如下图所示,右侧模块中会出现红圈将选中的控件标出。
    • 目录树圈选控件
  4. 选中某个控件之后,数据同学对该控件进行埋点配置,元素类型支持当前元素和同类元素。其中同类元素可以节省数据同学对于同一种类型的控件的多次配置。对于已经圈选出的控件,列表中会详细展示出相关的信息,并附上控件对于的位置截图,能够方便数据RD定位埋点的控件具体位置。
    • 埋点配置
  5. MTFlexbox管理后台根据前端上报的埋点信息,生成包含业务埋点的XML样式文件,供C端业务方后台调用。

    <?xml version="1.0" encoding="UTF-8"?>
    <Container>
    <Var auto-mge="true" name="ff510aa110844bb78c0b86fb04b26460" type="json">
    {
    "bid" : "xxxxx",
    "cid" : "sssss",
    "lab" : {
    "index" : "{_index}",
    }
    }
    </Var> <!-- 整个容器 -->
    <Container background="#FFFFFF" border-radius="10pt"
    click-mge4-report="{ff510aa110844bb78c0b86fb04b26460}"
    click-url="{_iUrl}" padding-left="10pt" padding-right="10pt">
    <!-- 左半部分 -->
    <Container style="flex-direction:column;justify-content:flex-start;margin-top:15pt;">
  6. 当客户端请求业务后台时,业务后台将包含业务埋点的XML样式文件下发给客户端,客户端根据配置完成埋点信息上报。

5. 总结与展望

目前MTFlexbox自动化埋点方案已经使用在美团首页、大搜等业务中,整体埋点成本降低了80%,上线后且无埋点故障。在此埋点方案的实现过程中,我们也踩了很多在设计之初没有预想到的坑,遇到了一些难点,详细设计问题和解决方案稍后的博客中的详细介绍,敬请关注美团技术团队公众号。

目前,我们基于MTFlexbox实现了View与埋点的自动化绑定,后期我们规划通过规范标准化后台下发的数据,包括业务数据和埋点数据,进而实现埋点数据的动态化下发和自动化绑定,进一步节省在埋点配置阶段和测试阶段的人力投入。

6. 参考资料

作者简介

叶梓、腾飞、田贝、张颖,美团终端业务研发团队研发工程师。

招聘信息

美团终端业务研发团队的职责是保障平台业务高效、稳定迭代的同时,持续优化用户体验和研发效率。团队负责的业务主要包括美团首页、美团搜索等千万级DAU高频业务以及分享、账号、音/视频等基础业务,支撑和对接外卖、酒店等30多个业务方。团队通过动态化能力建设,加快业务上线速度,帮助产品(PM)快速验证业务选型,做出业务决策;架构/服务标准化体系建设,提升前后端以及平台与业务线的沟通、合作效率;业务监控和体验优化,有效保障核心业务服务成功率的同时,提升用户使用美团App过程中的稳定性和流畅性。团队开发技术栈包括Android、iOS、ReactNative、Flexbox等。

美团终端业务研发团队是一个活力四射、对技术充满激情的团队,现诚聘Android、iOS工程师,欢迎有兴趣的同学投简历至 tech@meituan.com 。

MTFlexbox自动化埋点探索的更多相关文章

  1. 老李分享:Android -自动化埋点 3

    又一个问题,代码中的writeLog方法到底要记录哪些数据作为log信息呢?log信息中最重要的是能让开发者看出来哪个界面被打开或者哪个控件被点 击.对于界面,可以记录其类名:对于控件,一般没有确定的 ...

  2. 老李分享:Android -自动化埋点 2

    除了上述的事件,Android提供了一个OnTouchListener的监听器,当事件传递到控件的时候,如果控件注册了这个监听器,则会执行监听器中的onTouch方法.同时,如果它返回true,则事件 ...

  3. 老李分享:Android -自动化埋点 1

    老李分享:Android -自动化埋点   当我们开发一款Android应用上线后,希望能收集一些用户操作的行为数据,比如用户在某个页面点击了多少次,在某个控件被点击了多少次,在某个页面停 留了多少时 ...

  4. App可视化埋点技术原理大揭秘

    一.背景 运营者能够对用户行为进行分析的前提,是对大量数据的掌握.在以往,这个数据通常是由开发者在控件点击.页面等事件中,一行行地编写埋点代码来完成数据收集的.然而传统的操作模式每当升级改版时,开发和 ...

  5. Android快速开发框架——AndroidAnnotations(Code Diet)

    简介:AndroidAnnotations是一个依赖注入方式来简化代码结构 ,快速开发的开源框架,使结构代码更清晰,减少代码重复性.对今后我们做自动化测试和自动化埋点开发都会提高开发效率.跟我们之前使 ...

  6. 2020年,大厂常问iOS面试题汇总!

    Runloop & KVO runloop app如何接收到触摸事件的 为什么只有主线程的runloop是开启的 为什么只在主线程刷新UI PerformSelector和runloop的关系 ...

  7. 《Google软件测试之道》 第一章google软件测试介绍

    前段时间比较迷茫,没有明确的学习方向和内容.不过有一点应该是可以肯定的:迷茫的时候就把空闲的时间用来看书吧! 这本书,目前只是比较粗略的看了一遍,感触很大.以下是个人所作的笔记,与原文会有出入的地方. ...

  8. Selenium2学习-013-WebUI自动化实战实例-011-WebElement.getText()值为空问题探索及解决

    今天有个朋友在群里问 WebElement.getText() 值为空,当你发现取到的值为空的时候,会不会郁闷呢?明明看到的值不为空,脚本看着也没有问题啊,为何取到的值为空呢!!!万千纠结啊,若是长时 ...

  9. 为测试赋能,腾讯WeTest探索手游AI自动化测试之路

    作者:周大军/孙大伟, 腾讯后台开发 高级工程师 商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处.  WeTest导读 做好自动化测试从来不件容易的事情,更何况是手游的自动化测试,相比传 ...

随机推荐

  1. Appium+python自动化(二十一)- 让猴子按你指令大闹手机,让你成为耍猴高手 - Monkey(猴子) - MonkeyScript(超详解)

    简介 一年一度的暑假如期而至,每年必不可少的,便是<西游记>这部经典电视连续剧的播出,作为一名90后,对于这部经典剧的情谊,就是观看已成为一种习惯.依然深刻的记得,小时候妈妈为了催促我睡觉 ...

  2. 能访问的谷歌 http://209.116.186.231/

    能访问的谷歌 http://209.116.186.231/

  3. WePY的脱胎换骨

    对于前端来说,尤其是开发小程序的前端来说,WePY框架一定不陌生,他是一种小程序开发框架.而且是属于类Vue风格,掌握Vue再来学习WePY学习成本极低. 今天为啥要写这篇文章呢,因为在复习WePY时 ...

  4. 【原】docker部署单节点consul

    docker下部署单节点的consul,最重要的是在run consul时,配置-bootstrap-expect=1 docker run --name consul1 -d -p : -p : - ...

  5. 实现通过COM组件方式实现java调用C#写的DLL文件的完整demo

    最近因为工作需要,客户那边工程师使用的是JAVA语言开发的程序,我们这边平台中是用C#语言开发的,因为有些操作必须统一,所以我在网上查找解决方法,自己也实践过,在这里做个笔记吧,分享一下. 声明:下面 ...

  6. Linux vim环境设置

    //vim /etc/vimrc(管理员权限) 1. 显示行号: set number 或者  set nu 不显示行号: set nonu 2.自动缩进: set autoindent 3.C语言自 ...

  7. k8s1.9.0安装--完整集群部署

    三.完整集群部署 - kubernetes-with-ca 1. 理解认证授权 1.1 为什么要认证 想理解认证,我们得从认证解决什么问题.防止什么问题的发生入手.防止什么问题呢?是防止有人入侵你的集 ...

  8. python使用kazoo操作zookeeper时候出现的"kazoo.exceptions.ConnectionLoss"错误

    在往zk中写入数据的时候,突然遇到 “kazoo.exceptions.ConnectionLoss“错误,然而对zk链接进行检查,在set之前状态是”CONNECT“. 经过测试后发现是因为写入的字 ...

  9. <java程序大集合>

    1.以下关于开发java程序的描述错误的是(). A.开发java程序的步骤包括:编写源程序,编译,运行 B.编写的java源程序文件使用.java作为扩展名 C:java源文件经编译后,生成后娺为. ...

  10. 细说RESTFul API之版本管理

    目录 接口实现版本管理的意义 如何实现接口的版本管理 项目实战 接口实现版本管理的意义 API版本管理的重要性不言而喻,对于API的设计者和使用者而言,版本管理都有着非常重要的意义. 首先,对于API ...