有货APP团队开发一套数据采集SDK(组图)
优采云 发布时间: 2021-03-21 01:13有货APP团队开发一套数据采集SDK(组图)
随着库存应用程序的不断迭*敏*感*词*发,数据和业务部门对客户用户行为数据的要求越来越高;为了更好地监视APP使用状态,客户团队拥有有关APP本身操作的数据。需求变得越来越紧迫。迫切需要一套用于*敏*感*词*采集的工具,以自动和完全采集用户行为数据来满足各个部门的数据需求。
为此,Instock APP团队开发了一组数据采集 SDK。主要功能如下:
页面访问流程。用户在应用程序中浏览了哪些页面。浏览数据公开。用户在特定页面上查看了哪些产品。业务数据自动采集。用户在应用程序中单击了哪些位置以及触发了哪些操作。性能数据自动为采集。在用户使用APP的过程中,页面加载时间为多长时间,图片加载时间为多长时间,网络请求时间为多长时间,等等。
此外,所有数据采集应该是自动化且非侵入性的,也就是说,无需手动掩埋,就可以通过集成SDK来使用它,而无需尽可能少地更改或更改原创代码。
基于上述要求,AOP是技术解决方案的最佳选择,而在iOS上实现AOP则需要依靠Objective-C-Method Swizzle中运行时的黑魔法。踏入坑和填充坑的漫长旅程从这里开始,让我们逐一品尝实现的思想和方法。
页面访问流程
用户访问页面统计信息需要解决两个问题:
统计事件的入口点,即何时计数。统计数据字段,即要统计哪些数据。
整个过程如下:
统计事件的切入点
用户访问页面统计信息的一般思想是在View Controller生命周期方法中:
可以获得用户访问页面的路径,并且两个事件时间戳之间的差是用户停留在页面上的时间。
通常,我们APP中的View Controller继承自某个基类。我们可以在基类的相应方法中进行统计。但是,对于不继承自基类的View Controller,我们无能为力。
借助AOP,我们可以更优雅地完成此任务:只需在UIViewController的load方法中轻扫viewDidAppear和viewDidDisappear方法,就无需更改原创代码。
统计信息字段
根据数据要求,设置以下统计字段:
页面进入和退出事件在上述数据结构中报告。
还需要考虑几个问题:
1.如何定义PAGE_ID和SOURCE_ID
由于您需要统一iOS和Android的PAGE_ID,因此需要对其进行配置和发送。我在iOS端得到的是一个plist文件,该文件的键是View Controller类名的字符串表示形式,值是PAGE_ID。
2.如何获取PAGE_ID和SOURCE_ID
可以根据当前View Controller的类直接获取
PAGE_ID。 SOURCE_ID稍微复杂一些。根据APP页面的嵌套堆栈结构,需要确定具体的获取方法。通常,上一个View Controller的页面是从UINavigationController id的导航堆栈中获取的。
至此,页面访问流量统计已基本完成。根据页面进入和退出的PAGE_ID和SOURCE_ID,输入完整的用户浏览路径,并获得用户在每个页面上的停留时间。
浏览数据暴露
采集用户的浏览路径,以及在每个页面上花费的时间后,在某些页面(例如首页和产品列表页面)上,我们还想知道用户在页面,以查看已选择了哪些活动和产品,以便更好地为用户推荐喜爱的产品。
用户看到的屏幕区域被视为资源位,因此用户看到的内容由资源位组成。那么暴露的含义如下:
我们知道iOS中页面元素的基本单位是视图,因此我们只需判断视图是否在可见区域中,然后就可以知道当前视图上的资源位置是否需要公开,然后进行相应的曝光操作,采集数据,报告界面等。
从以上分析可以看出,有两个主要问题需要解决:
视图的可见性判断曝光数据采集视图的可见性判断
查询UIView类参考以查看setFrame:和layoutSubivews方法,这些方法可用于设置子视图的框架。每次更新观看次数时,都会调用此方法。因此,我们可以通过运行时选项卡来实现此方法,并添加一些与采集数据相关的操作。
我们向UIView添加了以下属性:
首先,阐明以下术语的定义和规则:
1.视图的子视图可以看到三个需要同时满足的条件:
相反,只要不满足以上任何条件,我们认为此子视图当前是不可见的。
2.将视图设置为可见
3.将视图设置为不可见
Swzzile setFrame :,请执行以下操作:
易用的layoutSubivews,调用yh_updateVisibleSubViews方法,该方法执行以下操作:
完成上述操作后,我们可以知道视图及其子视图是否可见。
查看曝光数据采集
为了获取与视图相对应的数据,还将以下属性添加到UIView:
然后还有两个问题:
视图公开数据的粒度组装视图及其子视图节点的公开数据的时间
浏览量数据的粒度
根据项目的实际经验,通常使用UITableViewCell或UI采集ViewCell作为最小粒度。同时,在最后一个节点的yh_exposureData字典中,添加一个键:isEnd以标识它是否是最后一个节点。
组装视图及其子视图的曝光数据的时间
通常,当最后一个节点的可见性发生变化时,请从下到上遍历最后一个节点的超级视图以组装所有数据。
因此,我们覆盖了setYh_viewVisible:方法,这是yh_viewVisible的set方法。请执行以下操作:
到目前为止,我们已经解决了视图可见性判断和曝光数据采集的问题。数据报告和策略将不会重复。
此方案有几个缺点
您需要手动设置曝光数据。您需要在正确的时间手动调用view.yh_viewVisible来触发数据采集,例如viewdidappear。需要消耗某些资源来计算视觉区域和曝光数据采集。
还有两个值得注意的问题:
UITableView将在setBounds:时更改视图框架,因此您需要调整setBounds:方法,需要在设置边界后调用[self yh_updateVisibleSubViews]; UIScrollView会在setContentInset:时影响视图的可见区域,因此需要使用setContentInset:方法,您需要在设置contentInset之后调用self.yh_viewVisibleRect = UIEdgeInsetsInsetRect(self.frame,contentInset);自动业务数据采集
自动业务数据采集是行业中没有隐患的流行数据采集。
传统客户用户点击数据采集基于手动埋入点。如果您对任何位置的数据感兴趣,请单击此处。用户操作后,将立即触发数据报告。手动掩埋的缺点很明显:错误的掩埋和丢失的掩埋。新版本发布后,经常有来自数据部门的小伙伴报告说,尚未报告特定点的问题,并且错误地报告了特定点的问题,并且开发同事也很痛苦。
没有掩埋点数据采集带来新的变化。首先,基本上避免了人工掩埋,个别情况需要特殊处理。其次,从有选择的采集数据中,它变成采集用户的所有点击和触摸数据的全部。
新变化也将带来新挑战。未埋数据采集的可能性仍基于Objective-C的运行时功能。在实践过程中,我们借鉴了iOS非埋入点数据SDK的总体设计和技术实施,而在实施过程中,我们借鉴了Sensors Analytics iOS SDK和Mixpanel iPhone。接下来,结合特定的实践,我们将介绍我们的实现思想和遇到的一些问题。主要分为以下三个方面:
如何确保自动采集点的唯一性。不同的点类型,需要使用哪些方法进行转换。在下雨的时候,这个坑就踩到了。如何确保自动采集点的唯一性
Auto 采集与手动埋入点分开,因此没有唯一的标识点。那么我们如何唯一地定位自动采集的点呢?一个容易想到的解决方案是:基于页面视图的树形结构。该解决方案可以分为两个问题:
如何定义视图的唯一标识符。该视图唯一地标识如何生成它。
视图唯一标识符(视图路径)的定义
我们规定典型的查看路径如下:
ViewController [0] / UIView [0] / UITableView [0] / UITableViewCell [0:2] / UIButton [0]
其中:
可以通过此标识符在当前页面的视图树结构中唯一标识此元素。标识的每个项目都由两部分组成:一个是当前元素类的字符串表示形式,另一个是同一级别元素中当前元素的序列号,从0开始计数。例如,当前第二个UIImageView是UIImageView 1。标识的最高层是当前视图所在的ViewController。对于UITableViewCell,UI采集ViewCell和类似的自定义组件,序列号部分由两部分组成:节和行,由以下部分拼接而成:徽标的末尾是当前被单击或触摸的元素。
如何生成视图唯一标识符
视图路径生成过程:从触发操作的最末端元素向上查询,直到找到ViewController。假设当前单击的视图是A_View,则从当前A_View遍历视图树,并将每个级别的数据存储在P_Array中。过程如下:
如果A_View是UI采集ViewCell类型,请获取A_View所在的UI采集View的indexPath以及P_Array推送路径信息[NSString stringWithFormat:@“%@ [%ld:%ld]”,[NSString stringWithFormat:@“%@ “,NSStringFromClass([A_View class])],(long)indexPath.section,(long)indexPath.row];如果A_View为UITableViewCell类型,则获取A_View所在的UITableView的indexPath,以及P_Array推送路径信息[NSString stringWithFormat:@“%@ [%ld:%ld]”,[NSString stringWithFormat:@“%@”,NSStringFromClass([A_View class])],(long)indexPath.section,(long)indexPath.row];遍历A_View.superview的所有子视图以获取A_View处于同一级别,并且相同类型的数字(索引)([A_View类]),P_Array推送路径信息[NSString stringWithFormat:@“%@ [%d]” ,NSStringFromClass([[A_View class]),index];获取A_View所在的控制器A_VC。如果A_View为A_VC.view,则遍历结束。如果A_View不等于A_VC.view,则A_View = A_View.superview,重复步骤1-4,直到A_View等于A_VC.view。遍历P_Array拼接A_View的完整路径。各种类型的点都需要使用毛毛雨方法
我们将APP中的用户操作分为四类:
UI采集View和UITableView的单元格单击事件。 UIControl(UISwitch,UIStepper,UISegmentedControl,UINavigationButton,UISlider,UIButton)控件的单击事件。 UIImageView和UITapGestureRecognizer触摸UILabel上的事件。 UITabBar,UIAlertView,UIActionSheet等的单击事件。
这四种操作都需要使用swizzle方法,如下表所示:
UI采集View,UITableView,UITabBar,UIAlertView,UIActionSheet以类似的方式实现。它们都是load方法中的swizzle setDelegate方法。在setDelegate之后,执行代理回调方法的swizzle操作。在回调方法中,首先执行原创逻辑。 ,然后获取相应的viewPath。
当UIControl组件回调到目标时,它将由UIApplication的sendAction:to:from:forEvent:调用,因此我们选择swizzle方法。在实践中,首先获取相应的视图路径,然后执行原创逻辑。原因是,如果首先执行原创逻辑,则页面可能会更改,并且所获得的View Controller将是错误的。
<p>UITapGestureRecognizer事件仅在UIImageView和UILabel上处理。 swizzle addGestureRecognizer:方法,首先执行原创逻辑,然后向视图添加自定义回调方法,以便在触发手势时也将调用自定义回调,此时我们将获得视图路径。