美学原理网易HubbleData无埋点SDK在iOS端的设计与贯彻

1.1 二种埋点的贯彻格局简介

埋点的章程分为三类:代码埋点、可视化埋点和无埋点。那里大致的介绍一下两种埋点形式:

(1)
代码埋点即是在代码的关键部位植入所要收集数据的N行代码,须要挖开产品我,浓密摸底产品的作业逻辑及项目结构,上面代码模拟突显的即是点击提交订单的时候HubbleData
SDK代码埋点;

代码埋点示例

(2)
可视化埋点即用可视化交互的方法圈选出所要采集数据的控件,当用户作为发出时,即可收集到对应的埋点数据。相比较于前方的代码埋点而言,可视化埋点可以缓解代码埋点代价大开支高的题材,然则力不从心灵活的自定义埋点属性。

可视化埋点流程

(3)
无埋点也叫全埋点,即不要求用户积极埋点,可以搜集用户所有的操作行为,同样使用可视化圈选,用户能够得到所想采集的埋点数据,可以化解可视化圈选中多少不可回溯的问题。下图给出了无埋点数据搜集的概括流程。

无埋点数据搜集流程

HubbleData
SDK的规划重点是代码埋点结合无埋点的数额搜集格局,其中也涉及到可视化埋点中的屏幕体系化及事件绑定机制,本文紧要介绍一下无埋点的布置性与完毕。

3.3.1 UITextField

UIText菲尔德(Field)是UIControl的一个子类,由于UIText菲尔德涉及到用户的难言之隐相比较多,比如用户名、密码、聊天文本等,所以HubbleData不会对此类的UIText菲尔德(Field)举行埋点的收集。

HubbleData主要收集的是UISearchBar中的UIText菲尔德,即UISearchBarText菲尔德(Field),并赢得搜索的文本内容,那对于部分电商类的App来说,可以较好的解析用户感兴趣的货物等,那是用作HubbleData
SDK无埋点的一个要求。

hook住sendAction:to:forEvent:后,如果对UISearchBarTextField的所有actions都进行hook的话,那么_searchFieldBeginEditing、_search菲尔德(Field)EndEditing等有着的action爆发的时候都会进展多少的收集,会征集到无数不行的信息,导致采集的数据错乱。HubbleData
SDK唯有当_search菲尔德EndEditing
action爆发时才会开展埋点,收集的properties为:

(1) type 为UIControl采集的事件类型,这里设置为searchBarEvent;
(2) page 为当前页面的名称,用于前端显示用;
(3) searchText 为_searchFieldEndEditing发生时采集到搜索框的搜索文字(此字段不为空);

如此那般就能对搜索框进行无埋点采集,并能收集搜索的公文内容。此格局只是在_search菲尔德(Field)EndEditing发生时征集数据,有可能该action执行时从没尽兴真正的物色操作,可能会与业务数据库的数目有出入,不过也可以比较准确的分析用户感兴趣的检索内容。

3.4 UITableView和UICollectionView的无埋点采集

本着UITableView和UICollectionView,HubbleData接纳的是先hook
UITableView和UICoolectionView的setDelegate:方法,然后找到呼应的delegate,然后再hook
delegate类中的tableView:didSelectRowAtIndexPath:方法和UICollectionView的collectionView:didSelectItemAtIndexPath:方法。那里以UITableView为例:

tableview

伊夫ntID根据上述介绍的法子赢得,只可是那里要注意的是,获取的并不是UITableView的唯一标识字符串而是对应的点击的cell的绝无仅有标识字符串。采集的properties为:

(1) type 为UITableView采集的事件类型,这里设置为tableViewSelectEvent;
(2) page 为当前页面的名称,用于前端显示用;
(3) section 为点击的cell所在的section;
(4) row 为点击的cell所在的row;

3.2 UIViewController的无埋点采集

重视是收集页面的生命周期,那里HubbleData选用的是hook
UIViewController的view威尔Appear方法,按照3.1交由的方法:

 [DASwizzler swizzleBoolSelector:@selector(viewWillAppear:)
                         onClass:[UIViewController class]
                       withBlock:executeAppearBlock];

当view威·尔(W·ill)Appear函数执行时,插入埋点的代码。HubbleData的统筹艺术为:

伊夫(Eve)ntID设置为固定的da_screen,即不会透过伊夫(Eve)ntID来差异各样页面的音信,HubbleData将顺序页面的区分消息放在了properties中,其中properties的安装为:

(1) $screenName 为当前页面的名称;
(2) $screenTitle 为当前页面的title,可为空;

还要HubbleData SDK提供了一个protocol <DAScreenAutoTracker>

即用户可以透过完毕该protocol,HubbleData
SDK会将screenTitle重临的值作为页面的称呼,trackProperties重临的属性插足对应页面的da_screen事件的特性中,作为用户访问该页面时的事件性质,screenUrl重返的字符串作为页面的Url,用于做一些页面之间相互跳转的解析等。

还要扩大了白名单设置,有部分UIViewController的新闻用户不想征集,可以经过设置白名单的情势,将有些不想征集的UIViewController过滤掉,比如说SFBrowserRemoteViewController,UIInputWindowController等种类自带的局地。

最终会调用track伊夫(Eve)nt记录该采访的轩然大波,同上述介绍的代码埋点一样,调用的章程如下:

[[DATracker sharedTracker] trackScreenEvent:@“da_screen” withAttributes:properties];

内部properties即为上述要收集的局地性能。

3.3.2 UIButton

UIControl中利用最多最普遍的是UIButton,由此对UIButton的采访万分紧要。在运用UIButton的时候可以自由的装置其title等属性来代表事情逻辑的不比景况。那里可以举一个简易的事例:基本app的报到页面,在用户名和密码都未输入时、都输入时以及登录中逐一状态,登录按钮的title、titleColor等特性可能都是分化的,即每一种button的样式都意味着着一种体制,可是得到的伊芙ntID是千篇一律的。针对此种意况,HubbleData会参与title、titleColor作为属性值,以便于后台举行更为的分析。

当按钮的两种情景只是二种差距的背景图片时,比近年来日头条依然微信的点赞等,其实是更换了一种背景图片,针对对那种状态处理,HubbleData则会赢得图片的imageName作为内部一个特性。

(1) type 为UIControl采集的事件类型,这里设置为buttonEvent;
(2) page 为当前页面的名称,用于前端显示用;
(3) title 为当前按钮的title;
(4) titleColor 为当前title的color,会转换成字符串的形式,rgba(r, g, b, alpha);
(5) imageName 为当前按钮的背景图片的name;
(6) frame 为UIButton的frame,用于分析同类元素,会转换成字符串的形式,rect(x, y, width, height);

可以看出,HubbleData还采集了该view的frame音信,首假设用来分析同类元素用的,下图给出一个简短的示范:

button

脚下有五个已关切的制品,当想总计用户拥有点赞的风云时,由于每个点赞的按钮都处在一个UITableViewCell中,在前面介绍的取得层级唯一路径UITableViewCell时的至极处理,由于各种按钮所在的cell的row分化,所以取得的每个按钮的事件的唯一伊芙ntID都是见仁见智的,这样后端在条分缕析的时候,无法归类同类元素。当HubbleData给出frame时,后端可以依据frame归类出同一类按钮的风浪,具体的归类策略那里不再介绍。

四、总结

小说主要介绍了HubbleData无埋点SDk在iOS端的设计与贯彻,涉及的关键内容:事件唯一ID的确定和一些无埋点的完毕,当然在无埋点SDK的宏图开发中还遭受了各样各类的题目。鉴于文章的字数已经较长,一些问题的解决以及关键技术的落到实处,比如精准渠道追踪、hook冲突解决、代码埋点的兑现、显示屏系列化以及可视化圈选部分的始末,本篇文章不再介绍,将会在此起彼伏作品中一连介绍。

3.3 UIControl的无埋点采集

针对UIControl,HubbleData选取的是hook
UIControl的sendAction:to:for伊夫(Eve)nt:方法。由官方文档可见,在UIControl执行相应的action时都会率先调用sendAction:to:for伊芙(Eve)nt:方法,完结如下:

control

设想到UIControl的子类较多,所以HubbleData选择了内部使用较多的二种举办了新鲜的分析:紧即使UIText菲尔德、UIButton和UISwitch,其他的暂时未做特殊分析。具体的埋点的搜集安顿为:

任凭哪一种UIControl,伊夫ntID均运用的是第三有些介绍的绝无仅有标识字符串的SHA256编码值,不过相关采访properties有所出入。

3.3.4 其余UIControl

其余的只是采集type,page属性,方今未做过多的处理。

(1) 各类子页面的controller分裂?

假设pageViewController中的种种子页面不一样,即使延续2.2节HubbleData会参加页面controller的音信来分别那些分裂的子页面,不过也许会出于每个子页面加入的次第差别,导致每一回app进来的时候同一个页面的事件会博得分裂的伊芙(Eve)ntID,举例来说雅培(Abbott)下,如上图1所示,比如前七个子页面是ViewController1,
ViewController2, ViewController3,
ViewController4,那类pageViewController除非设置三个子页面同时预加载出来,那么此时的得到的层级路径为:

ViewController1对应路径为:superview(0)_subControllerView(0) 
ViewController2对应路径为:superview(0)_subControllerView(1)
ViewController3对应路径为:superview(0)_subControllerView(2)
ViewController4对应路径为:superview(0)_subControllerView(3)

但是app基本都不会预加载出装有页面,对于用户不感兴趣的页面完全没要求一次性全体加载处理,唯有当用户选用了该条款时,该对应的子页面才会加载出来,假诺前几日用户点击的相继是ViewController1,ViewController3,ViewController4,ViewController2,由于addChildViewController或者addSubView的逐一的转移,那么此时收获的层级路径为:

ViewController1对应路径为:superview(0)_subControllerView(0) 
ViewController2对应路径为:superview(0)_subControllerView(3)
ViewController3对应路径为:superview(0)_subControllerView(1)
ViewController4对应路径为:superview(0)_subControllerView(2)

可以窥见,index值变了,层级路径不唯一了,那么无埋点采集的伊夫ntID可能会由于用户采取页面顺序的不比而各异,造成埋点数据的杂乱无章。

HubbleData对于此类页面的拍卖是,碰到此类页面,即不用index标注,所以会联合的标识成:

ViewController1对应路径为:superview(0)_subControllerView 
ViewController2对应路径为:superview(0)_subControllerView
ViewController3对应路径为:superview(0)_subControllerView
ViewController4对应路径为:superview(0)_subControllerView

后续可以透过区其余页面的controller的类名获取其分歧的唯一标识字符串。

2.1.2 三种越发景况的处理

2.1.1关键讲的是一对常常view的层级结构的path构造格局,不过有部分非同平日情况须要特地的设想处理:

  • UITableViewCell

由于UITableViewCell具有可复用的体制,当一个页面中在相连滚动的时候,cell在相连的复用,如果还使用2.1.1中介绍的主意来赢得index索引值话,那么会滋生上上下下页面无埋点数据收集的杂乱。

当得到当前UITableViewCell的index时,可以动用indexPath参数进行交流,那一个参数可精确的收获section和row的值,唯一的附和每一个cell。唯一层级路径的款型可以自定义配置,HubbleData的安装格局为:类名+(section:
row:),下边给出一个示范:

MyTableViewCell(section:0 row:7)
  • UICollectionViewCell

UICollectionViewCell的path生成原理同UITableViewCell,HubbleData的安装方法为:类名+(section:item:),上面给出一个示范:

MyCollectionViewCell(section:0 item:7)
  • UIControl

事实上UIButton也终究一种家常view的一种,半数以上情况下,使用上述的层级结构path以及页面类名的组成可以唯一的规定当前UIControl的唯一标识符,可是有一种独特的情事,当作为UINavigationItem时会出现尤其景况,上边的所付出的五个例证。

bar1

bar2

当点击首个NavigationBar的左侧的按钮时,获得的层级路径为:

...UIViewControllerWrapperView(0)_UIView(0)_UILayoutContainerView(0)_UINavigationBar(0)_UIButton(1)

解析可见,左边的安装按钮的目录为0,所以左边的按钮索引为1。同时得到的眼前页面为:UINavigationController。

当点击第四个页面的同一个项目标按钮时,即一律标有数字7的item时,此时到手的层级路径为:

...UIViewControllerWrapperView(0)_UIView(0)_UILayoutContainerView(0)_UINavigationBar(0)_UIButton(2)

可以发现此时的按钮的目录变成了2,已经不一样于上述第三个NavigationBar的同一个按钮的层级路径了,经过分析,索引值为1的按钮是最左边的报表的极度item,经过认证可以收获其层级路径:

...UIViewControllerWrapperView(0)_UIView(0)_UILayoutContainerView(0)_UINavigationBar(0)_UIButton(1)

获取的页面为:UINavigationController。

实质上那种页面很广泛,由于页面的切换,NavigationBar上的一对按钮的岗位也许顺序会打乱,导致同一个作用的NavigationItem已经不可以确定标识唯一,即便是取得了眼前按钮所在的页面也无力回天区分,因为获取的都是UINavigationController。从上边的剖析可以见到,这种状态竟然会造成严重混乱的数码收集。

其实仔细分析一下,若是条分缕析得出该UIControl是在UINavigationBar上,则无需安装其相应的index值,即上述的装有navigationItem的层级结构路径都为:

...UIViewControllerWrapperView(0)_UIView(0)_UILayoutContainerView(0)_UINavigationBar(0)_UIButton

即都不做区分。

HubbleData选拔增添一种新的性能来分别各样item,其实很明显可以看出来,那个item的履行的action肯定是见仁见智的,所以取其action属性来不相同,最后的区分格局如下:

path(...UIViewControllerWrapperView(0)_UIView(0)_UILayoutContainerView(0)_UINavigationBar(0)_UIButton)&actions(button1Click:)
path(...UIViewControllerWrapperView(0)_UIView(0)_UILayoutContainerView(0)_UINavigationBar(0)_UIButton)&actions(button2Click:)

那般,HubbleData就足以规范的界别差其他item了,同时达成平等种功用的item,由于其action相同,所以也会规范的标识其唯一性。

  • UIAlertController

出于分化的UIAlertController在增选确定、打消等选项时,选择的进行唯一层级路径判定的view须求展开一定的处理,同时为了有限协理不一致的UIAlertController处于同一地点的拔取的埋点伊芙(Eve)ntID不一致,这里在布局唯一标志字符串的时候还要投入该UIAlertController的message和title音讯。3.5小节中会进行相关无埋点采集的牵线。

  • viewController的嵌套

一般情况下,普通的view只需坚守一般的层系路径收集index即可,但是当存在pageViewController时,如下图所示分别交付了一个横向滚动(以企业考拉app为例)和纵向滚动(以店堂严选app为例)的app的截图的演示:

实在可以见见,pageViewController会应用到丰裕多彩app中,所以那类app在选取过程中的无埋点问题进一步要考虑。

>三、无埋点的采集的落实

3.3.3 UISwitch

好像于UIButton,只然而那里要收集switchState,即眼前的开关状态,具体的募集属性为:

(1) type 为UIControl采集的事件类型,这里设置为switchEvent;
(2) page 为当前页面的名称,用于前端显示用;
(3) switchState 为switch的开关状态;
2.1.1 普通view的层级结构path构造

层级结构path紧如果基于页面的控件树构造而成,每个view都有superview与subviews的性能,将每一个view的superview作为树的父节点,将其subviews作为子节点,那样就能把一切app上的有所view组成一棵高大的控件树,其中树的顶层是UIWindow,然后是每一个view节点依次向下开展。下图给出一个简单易行的控件树的布局图。

空中树结构

上边会详细介绍一下HubbleData的唯一标识路径的构造方式。

不同类

同类

像上图1所示,假诺一个view的subviews中都是分化品类的,比如像下图图1所示的控件树那样,可以唯一标识UILabel和UIButton控件为:

UIView_UILabel
UIView_UIButton

不过真的的页面是不会像可以中的所有控件都是分化类其他,可以说那种极端景况基本不设有,如若依然听从上述的法门来社团路径的话,七个UILabel都会被标识成UIView_UILabel,那肯定不能区分多少个控件。由此唯有是每个控件节点的不二法门名称是无力回天唯一标识那些控件的,那里HubbleData参加了此控件节点在父视图中的index。比如上图2,可以将四个UILabel标识为:

UIView(0)_UILabel(0)
UIView(0)_UILabel(1)

那里借使父视图是index为0的一个节点,那样就足以完全的界别出四个控件了。

那就是说余下的题目就是各种UIView index索引值的确定。

种种UIView都有subviews属性,每一个子视图都有一个被addsubView的顺序,其实要拿的那些index就是子视图被add的先后,那么该怎么得到那个顺序呢,在苹果的官方证实文档中,岁UIView的subviews属性,是如此介绍的:

@property(nonatomic, readonly, copy) NSArray *subviews

You can use this property to retrieve the subviews associated with your custom view hierarchies. 
The order of the subviews in the array reflects their visible order on the screen.

即每一个子视图在那几个subviews数组中的索引就是HubbleData要拿的index。

针对复杂的视图格局,如下图所示,根据上述的层级结构路径构造方法得到的唯一层级路径为:

UIView(0)_UILabel(0)
UIView(0)_UIButton(1)
UIView(0)_UIButton(2)  

混合

从上述的解析可见,根据上述介绍的方法举办view的绝无仅有层级路径标识,对一大半的页面来说已经够用,不过对于有些尤其灵活点的页面,由于一些政工须求等原因,开发人士日常会调用removeFromSuperview,
insertSubview:atIndex:, insertSubview:
belowSubview:等函数,都会大幅度的熏陶整个页面的subviews的索引值,比如现在本身将上图所示的UILabel移动到八个UIButton的末端,那么得到的唯一层级路径为:

UIView(0)_UIButton(0)
UIView(0)_UIButton(1)
UIView(0)_UILabel(2)  

混合

能够发现,唯一层级路径已经被改变,可是整个页面却未曾暴发变化,不仅会发出新的事件(比如UIButton(0),UILabel(2)),连UIButton(1)事件的收集也会出错,就算是例外的轩然大波,却收获了不一样的eventID,所以必要增强社团的层级结构路径的稳健型。

正像刚刚提到的,差距门类的UIView不需求做index的分歧,那么在获取那些index的时候,不是简不难单的从subviews这几个数组中拿走其对应的索引值,而是举行一个简便的同类归并再取索引值,一个很简短的处理。

for (UIView *view in subviews) {
    if ([NSStringFromClass([subview class]) isEqualToString:NSStringFromClass(class)]) { //class为待筛选的类
        [array addObject:view];
    }
}

诸如此类就可以取得array中的index作为其真正的索引值,得到的层级结构路径为:

UIView(0)_UILabel(0)
UIView(0)_UIButton(0)
UIView(0)_UIButton(1) 

那会儿无论UIlabel的任务位于哪儿,都不会改变那一个途径的构造样式,大大增添了稳健型。其实也能窥见,那只是只好进步稳健型,并不可能从根本上解决那一个题材,比如果我把三个UIButton的逐一沟通了,或者去除了第三个,此时如故会获取一些不规范的层级路径。此题材会两次三番解决,会日益引入误差容量和相似度那一个概念,即即便在误差范围内,则会进行进一步的匹配,具体的解决方案本篇不在介绍。

3.1 AOP 简介

上边讲一下无埋点的现实贯彻,用到的重大是AOP(Aspect-Oriented-Programming),面向切面编程,面对的是处理过程中的某个步骤和方法。在运行时,动态的将代码插入到类的创建办法、指定地点上的编程思想就是面向切面编程。熟知iOS
Runtime的应当很通晓,相关的介绍小说也很多,那里不再过多的废话。

HubbleData无埋点的完成重大就是借助AOP,hook对应类的点子,并在原完毕代码的底蕴上插入自己定义的埋点的代码,当该类的被hook的函数执行时,就能促成无埋点数据搜集的出力。下边给出HubbleData里面Method
Swizzling的一个简练的兑现。

Method Swizzling

上述代码只是给出了一个简短的已毕的逻辑结构,new_swizzledMethod也只是selector没有参数的场馆(除去self和_cmd),真正在埋点的处理进程必要考虑的景观相比较多。

二、事件唯一ID的规定

为了兑现在可视化圈选的时的事件的唯一性,每一个无埋点的事件采访都必须有且仅有一个唯一的标识符来区分区其余轩然大波。分歧于代码埋点,用户可以自定义的布署自己所需的伊芙ntID,无埋点进度中,须要SDK自己配置每一个搜集事件的伊芙(Eve)ntID,通过可视化圈选的操作,筛选出相应的伊夫(Eve)ntID所对应的数据新闻。HubbleData采纳的是社团view唯一标识字符串的方式去唯一的标识那样的一个轩然大波,主要由view的层级结构path路径、该view的随处页面类名以及view所带的一部分本身定位属性等构成,并透过SHA256编码来获取唯一的伊芙(Eve)ntID。

上边将整种类统介绍一些轩然大波唯一ID的生成进程。

2.2 当前页面controller的收获

看上去,半数以上情景下2.1的view的层级结构path已经主导规定view的绝无仅有标识字符串,不过普遍存在这么一种处境,当同一个页面跳转多个不等的页面时,假若那七个例外的页面上都取第二个按钮的层级路径,获得的简化后的结果都如下所示:

.../UINavigationTransitionView(0)/UIViewControllerWrapperView(0)/UIView(0)/UIButton(0)

是无力回天展开那五个页面上的按钮区分的,其实页面的类名是分其余一个最直白的主意。HubbleData是按照上面的主意得到某个view所在的controller的类名的。

获取当前controller示例

将view的层级路径结合当下页面的名目,已经可以缓解掉一大半的唯一标识字符串的题材了。

此处须求专注的某些是,当页面类型一样,只是填充的model分歧时,比如浏览商品详情时,所进入的页面都是一个,只是model分裂,近来HubbleData对那种气象临时未做处理。后续可参照著作3.2节UIViewController的无埋点采集,对部分页面,用户可以自定义诸如screenTitle的字段,定义该页面的称号,比如screenTitle包涵产品唯一ID时,此时将该字段到场唯一标识字符串中即可区分。近期那块还未做连锁处理,那里只是提供一个简便的解决思路。

0 引言

近年在背负集团的HubbleData的埋点SDK的支付任务,产品的雏形其实在几年前就曾经有了,集团内部的例如考拉、易信、LOFTER、美学、漫画等多款产品都已接入使用。

下图给出HubbleData SDK某个应用的部分分析的显示页面:

(1)概览示意图

事件

(2)事件分析示意图

事件

(3)实时分析示意图

事件

除此以外HubbleData平台还持有留存分析、漏斗分析、粘性分析、数据看板等多种功用,方便有关负责人士对产品用户作为展开更为的切磋分析。

老版本的SDK的筹划是代码埋点完结的,即便对于一些较为成熟的成品,代码埋点完全可以达到产品方的急需,不过对于有些新启动或者需频仍改变的需求的新产品等,考虑到其有限帮助的本钱大,代价高等缺点,HubbleData无埋点SDK的安插就显得尤为重大了。

本人根本担负iOS端无埋点以及可视化圈选的办事,小说首要系统讲授一下HubbleData无埋点SDK在iOS端的设计与落实和部分有关问题的缓解,后续将针对所有埋点的贯彻流程与可视化圈选等情节再作分享。

1.2 无埋点SDK设计详细流程

下图给出HubbleData无埋点SDK在iOS端的设计落成:

无埋点详细安插流程

从上图可以看来,HubbleData的无埋点是在代码埋点的基本功上落到实处的,所处无埋点的难关也就集中在以下七个位置:

(1)自动获取埋点的EventID
(2)自动获取埋点的时机
(3)自动获取埋点需采集的属性

本文紧要就那多少个地点拓展解析,第二局地重视讲一下事件唯一ID的规定,第三部分至关首要讲一下无埋点的收集的贯彻,首如果各样风浪时有暴发采集的机遇以及待采集的特性的配置。

HubbleData
SDK还提到到广大任何职能,包蕴显示屏体系可视化、代码埋点、精准渠道追踪等,那里不再介绍,后边会陆续分享相关的技巧已毕。

一、埋点简介

3.5 UIGestureRecognizer的无埋点采集

在iOS开发中,常常会利用部分手势来拍卖部分点击的操作,所以也有必不可少对UIGestureRecognizer进行hook。HubbleData
并不是一贯针对UIGestureRecognizer那些类进行hook,而是hook
UIView类的addGestureRecognizer:方法,已毕如下:

gesture

经过hook
addGestureRecognizer:方法,可以得到该UIView所添加的UIGestureRecognizer,那里只对UITapGestureRecognizer和UILongPressGestureRecognizer进行处理,其余的手势暂未做处理。得到相应的UIGestureRecognizer,添加一个action,当该手势执行的时候,同样会履行该action,在action中举办埋点的操作。

此地得到的是UIGestureRecognizer所在的UIView的唯一标识标识字符串编码作为伊芙(Eve)ntID,采集的性能为:

(1) type 为UIGestureRecognizer采集的事件类型,这里设置为gestureTapEvent;
(2) page 为当前页面的名称,用于前端显示用;

UIAlertController的出色处理

此间要求对UIAlertController做一个详尽的注解,因为UIAlertController在点击诸如打消、确定的选项按钮时,也会进展手势的埋点采集,不过在iOS9和iOS10上稍微有些不一致。

此处先以iOS9为例,其target是功用在_UIAlertControllerView那么些系统的私有类上的,如果直接对那个_UIAlertControllerView举办唯一标识字符串的结构,则撤除和确定选项获得的伊芙(Eve)ntID是同等的,那样将不可以准确的剖析出用户的精选,所以必须以每个选项view作为独立的唯一标识字符串进行分析才能规范区分。通过取得_UIAlertControllerView的_actionViews变量,就能获取各样选项的view,那里要做一个概括的点击坐标获取,判断所点击的区域位于的actionView,具体完毕如下:

那边在基准判断时设定gesture.state ==
UIGestureRecognizerStateBegan,是由于UILongPressGestureRecognizer会再三再四五遍调用action,由此那里须求参预事件的气象举行区分,幸免举行一次相同的多寡收集。

iOS10下的UIAlertController的中间贯彻做了一部分变动,其target变换成在_UIAlertControllerInterfaceActionGroupView这么些系统的私有类上的,然后须求展开一定的拍卖,获取UIInterfaceActionSelectionTrackingController的_representationViews变量,遍历得到种种选项的view,具体落到实处如下:

通过上述的分析可以窥见,那样纵然能分别同一个UIAlertController的不一样的操作选项,不过可能无法区分出分化UIAlertController的介乎同一地方的选项,所以那里还要加入UIAlertController额外的属性信息来分别。

前方也有提过,可以很简单的想到UIAlertController的message和title可以较好的拓展区分,所以在原始的层级路径和如今页面的功底上,还要加上message和title以组合唯一标识字符串。给出一个样例:

path(UIWindow(0)__UIAlertControllerView(0)_UIView(0)_UIView(0)_UIView(0)_UICollectionView(0)__UIAlertControllerCollectionViewCell(section:0 item:0)_UIView(0)__UIAlertControllerActionView(0))&controller(UIAlertController)&message(确认退出群聊吗?)&title(退群)

2.1 控件的层级结构path构造

(2) 各样子页面的controller相同?

实在做过此类页面的着力应该都耳熟能详,很多景色下子页面都是公共的,只不过是填写的model差异而已,那么碰着那种场地,如果是按照问题1的缓解思路,即便根据2.2拿到了当下页面的controller,那么仍旧不能区分出这么些页面,所以依旧必要设置新的富有辨识度的index。

实质上通过pageViewController可以发现,用户可以透过左右滑行或者前后滑动来切换子页面,表达拥有的子页面都是松手在一个scrollView之中,那么就足以从这几个scrollView入手,重新确定index。上边给出HubbleData解决这一个问题的方法。

一起头想使用当前scrollView的contentOffset整除此pageViewController的页面宽度和惊人所获取的值作为区分子页面的index,不过考虑到可能contentOffset的一连变化以及子页面横跨pageViewController整数倍宽度的疆界时,可能会导致获取的index不唯一的事态,所未来来利用该子页面的苗头地方整除pageViewController的相应地宽度和可观得到相应地index。具体的落到实处如下,其中controller为当下的页面:

 if (view == controller.view || view == controller.view.superview) {
      NSInteger index_x = view.center.x / [view superview].frame.size.width;
      NSInteger index_y = view.center.y / [view superview].frame.size.height;
      NSString *path = [NSString stringWithFormat:@"%@(indexx:%ld indexy:%ld)",  
                        NSStringFromClass([view class]), index_x, index_y];
  } 

据此一律针对上述(1)所提交的多少个ViewController1,优化后的到的唯一的标识为:

ViewController1对应路径为:superview(0)_subControllerView(indexx:0 indexy:0)
ViewController2对应路径为:superview(0)_subControllerView(indexx:1 indexy:0)
ViewController3对应路径为:superview(0)_subControllerView(indexx:2 indexy:0)
ViewController4对应路径为:superview(0)_subControllerView(indexx:3 indexy:0)

这样就是各类子页面的controller相同,也能经过优化后的index来分别种种不一样的子页面。当然这种只是针对嵌套scrollView的子页面的意况,不过能缓解一大半的此类问题,对于有些其余的独特处境等,需详细分析页面布局举办辨析。