6748如何设置edma为事件触发方式_埋点全解 5 :控件点击事件全埋点

1db83647f70c34b49291e9ca390f32a2.png

1、原理概述

在本章,我们主要介绍如何实现控件点击事件 ($AppClick)的全埋点。在介绍如何实现之前,我们需要 先了解一下,在 UIKit 框架下,处理点击或拖动事件的 Target-Action 设计模式。

(1)Target-Action

Target-Action,也叫目标-动作模式,即当某个事件发生 的时候,调用特定对象的特定方法。

比如,在 LoginViewController 页面,有一个按钮,点击 按 钮 时,会 调 用 LoginViewController 里 的 - loginBtnOnClick 方法,“特定对象”就是 Target,“特定 方法”就是 Action。也即 Target 是 LoginViewController, Action 是 - loginBtnOnClick 方法。

Target-Action 设计模式主要包含两个部分:

  • Target 对象:接收消息的对象
  • Action 方法:用于表示需要调用的方法

Target 对象可以是任意类型的对象。但是在 iOS 应用程序 中,通常情况下会是一个控制器,而触发事件的对象和 Target 对象一样,也可以是任意对象。例如,手势识别器 UIGestureRecognizer 就可以在识别到手势后,将消息发 送给另一个对象。Target-Action 设计模式,最常见的应 用场景还是在控件中。iOS 中的控件都是 UIControl 类或 者其子类,当用户在操作这些控件时,会将消息发送到指 定的对象(Target),而对应的 Action 方法必须符合以下 几种形式之一:

 - (void)doSomething; 
- (void)doSomething:(id)sender; 
- (void)doSomething:(id)sender forEvent:(UIEvent *)event;
- (IBAction)doSomething; 
- (IBAction)doSomething:(id)sender; 
- (IBAction)doSomething:(id)sender forEvent:(UIEvent *)event; 

其中以 IBAction 作为返回值类型的形式,是为了让该方 法能在 Interface Builder 中被看到;sender 参数就是触 发事件的控件本身;第二个参数 event 是 UIEvent 的对象, 封装了触摸事件的相关信息。

我们可以通过代码或者 Interface Builder 为一个控件添加 一个 Target 对象以及相对应的 Action 方法。

若想使用代码方式添加 Target-Action(我们也会用 Target-Action 表示:一个 Target 对象以及相对应的 Action 方法),可以直接调用控件对象的如下方法:

- (void)addTarget:(nullable id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents; 

我们也可以多次调用 - addTarget:action:forControlEvents: 方法给控件添加多个 Target-Action,即使多次调用 - addTarget:action:forControlEvents: 添 加 相 同 的 Target 但是不同的 Action,也不会出现相互覆盖的问题。 另外,在添加 Target-Action 的时候,Target 对象也可以 为 nil(默认会先在 self 里查找 Action)。

当我们为一个控件添加 Target-Action 后,控件又是如何 找到 Target 对象并执行对应的 Action 方法的呢?

在 UIControl 类中有一个方法:

 - (void)sendAction:(SEL)action to:(nullable id)target forEvent:(nullable UIEvent *)event;

如果控件被用户操作(比如点击),首先会调用这个方法, 并将事件转发给应用程序的 UIApplication 对象。 同时,在 UIApplication 类中也有一个类似的实例方法:

- (BOOL)sendAction:(SEL)action to:(nullable id)target from:(nullable id)sender forEvent:(nullable UIEvent *)event;

如果 Target 对象不为 nil,应用程序会让该 Target 对象 调用对应的 Action 方法响应事件;如果 Target 对象为 nil,应用程序会在响应者链中搜索定义了该方法的对象 ,然后执行 Action 方法。

基于 Target-Action 设计模式,我们有两种方案可以实 现 $AppClick 事件的全埋点。

下面,我们逐一进行介绍。

(2)方案一

通过 Target-Action 执行模式可知,在执行 Action 方法 之前,会先后通过控件和 UIApplication 对象发送事件 相关的信息。因此,我们可以通过 Method Swizzling 交 换 UIApplication 的 - sendAction:to:from:forEvent: 方法,然后在交换后的方法中触发 $AppClick 事件,并根 据 target 和 sender 采集相关的属性,即可实现 $AppClick 事件的全埋点 。

对于 UIApplication 类中的 - sendAction:to:from:forEvent: 方法,我们以给 UIButton 设置 action 为例,详 细介绍一下。

[button addTarget:person action:@selector(btnAction) forControlEvents:UIControlEventTouchUpInside]; 

参数

  • action:Action 方法对应的 selector,即示例中的 btnAction。
  • target:Target 对象,即示例中的 person。如果 Target 为 nil,应用程序会将消息发送给第一个响应者,并从第 一个响应者沿着响应链向上发送消息,直到消息被处理 为止。
  • ender:被用户点击或拖动的控件,即发送 Action 消息 的对象,即示例中的 button。
  • event:UIEvent 对象,它封装了触发事件的相关信息。

返回值

如果有 responder 对象处理了此消息,返回 YES,否则 返回 NO。

一般情况下,对于一个控件的点击事件,我们至少还需要 采集如下信息(属性):

  • 控件类型($element_type)
  • 控件上显示的文本($element_content)
  • 控件所属页面,即 UIViewControlle(r$screen_name)

基于目前的方案,我们来看如何实现采集以上三个属性。

获取控件类型

获取控件类型相对比较简单,我们可以直接使用控件的 class 名称来代表当前控件的类型,比如可通过如下方式 获取控件的 class 名称:

NSString *elementType = NSStringFromClass([sender class]) 

获取显示文本

获取控件上的显示文本,我们只需要针对特定的控件,调 用其相应的方法获取文本即可。

获取控件所属页面

如何知道一个 UIView 所属哪个 UIViewController 呢? 这就需要借助 UIResponder 了!

大家都知道,UIResponder 类是 iOS 应用程序中专门用 来响应用户操作事件的,比如

  • Touch Events:即触摸事件
  • Motion Events:即运动事件
  • Remote Control Events:即远程控制事件

UIApplication、UIViewController、UIView 类都是 UIResponder 的子类,所以它们都具有响应以上事件的 能力。另外,自定义的 UIView 和自定义视图控制器也都 可以响应以上事件。在 iOS 应用程序中,UIApplication、 UIViewController、UIView 类的对象也都是一个个响应者,这些响应者会形成一个响应者链。一个完整的响 应者链传递规则(顺序)大概如下:UIView → UIViewController → RootViewController → Window → UIApplication → UIApplicationDelegate,可参考下图 1 所示(此 图来源于苹果官方网站) 。

6034920d98107f451bb508a4b9d8262d.png
图 1 事件响应者链

注意:对于 iOS 应用程序里实现了 UIApplicationDelegate 协议的类(通常为 AppDelegate),如果它是继承自 UIResponder,那么也会参与响应者链的传递;如果不是继 承自 UIResponde(r例如 NSObject),那么它就不会参与 响应者链的传递。

通过图 1 可以知道,对于任意一个视图来说,都能通过响 应者链找到它所在的视图控制器,也就是其所属的页面,从 而可以达到获取它所属页面信息的目的。

(3)方案二

当一个视图被添加到父视图上时,系统会自动调用它的 - didMoveToSuperview 方法。因此,我们可以通过 Method Swizzling 交换 UIView 的 - didMoveToSuperview 方法, 然后在交换方法里,给控件添加一组UIControlEventTouchDown 类型的 Target-Action,并在 Action 里触发 $AppClick 事件,从而达到 $AppClick 事件全埋点的效果, 这就是我们的方案二。

(4)方案总结

方案一和方案二,其实都是运用了 iOS 中的 Target-Action 模式。这两种方案,各有优缺点。

对于方案一:如果给一个控件添加了多个 Target-Action 方 法,会导致多次触发 $AppClick 事件。

对于方案二:由于我们 SDK 为控件添加了一个默认触发类型的 Action 方法,因此,如果开发者在开发过程中使用 UIControl 类的 allTargets 或者 allControlEvents 属性进 行一些逻辑判断,有可能会引入无法预料的问题。

因此,在选择方案的时候,可以根据自己的实际情况和需求,来确定最终的实现方案。


关于 iOS 应用程序状态更详细的内容,及 iOS 更多内容,可点击下方白皮书了解:

https://www.sensorsdata.cn/school/library/35c8fced158dfe83e838208c1c77cbd5?utm_source=wechat1&utm_medium=Link&utm_term=%E4%B8%8B%E8%BD%BD%E7%99%BD%E7%9A%AE%E4%B9%A6&utm_content=iOS%E5%85%A8%E5%9F%8B%E7%82%B9%E6%8A%80%E6%9C%AF%E7%99%BD%E7%9A%AE%E4%B9%A6&utm_campaign=%E5%86%85%E5%AE%B9%E8%90%A5%E9%94%80​www.sensorsdata.cn
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值