iOS 全埋点-控件点击事件

1,476 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第22天,点击查看活动详情

Target-Action设计模式

在具体介绍如何实现之前,我们需要先了解在UIKit框架下点击或拖动 事件的Target-Action设计模式。
Target-Action模式主要包含两个部分。

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

Target可以是任意类型的对象。但是在iOS应用程序中,通常情况下会 是一个控制器,而触发事件的对象和接收消息的对象(Target)一样,也可 以是任意类型的对象。例如,手势识别器UIGestureRecognizer就可以在识 别到手势后,将消息发送给另一个对象。

当我们为一个控件添加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,应用程序会让该对象调用对应的方法响应事件;如果Targetnil,应用程序会在响应链中搜索定义了该方法的对象,然后 执行该方法。

基于Target-Action设计模式,有两种方案可以实现$AppClick事件的全埋点。下面我们将逐一进行介绍。

方案一

描述

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

代码实现

新建一个UIApplication的分类

+ (void)load {
    [UIApplication sensorsdata_swizzleMethod:@selector(sendAction:to:from:forEvent:) withMethod:@selector(CountData_sendAction:to:from:forEvent:)];
}

- (BOOL)CountData_sendAction:(SEL)action to:(id)target from:(id)sender forEvent:(UIEvent *)event {
    [[SensorsAnalyticsSDK sharedInstance] track:@"$appclick" properties:nil];
    return  [self CountData_sendAction:action to:target from:sender forEvent:event];
}

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

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

获取控件类型

先为你介绍一下NSObject对象的继承关系图

image.png

从上图可以看出,控件都是继承于UIView,所以获取要想获取控件类型,可以声明UIView的分类

新建UIView的分类(UIView+TypeData)

UIView+TypeData.h

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIView (TypeData)

@property (nonatomic,copy,readonly) NSString *elementType;

@end

NS_ASSUME_NONNULL_END

UIView+TypeData.m

#import "UIView+TypeData.h"

@implementation UIView (TypeData)

- (NSString *)elementType {
    return  NSStringFromClass([self class]);
}
@end

获取控件类型的埋点实现

+ (void)load {
    [UIApplication sensorsdata_swizzleMethod:@selector(sendAction:to:from:forEvent:) withMethod:@selector(CountData_sendAction:to:from:forEvent:)];
}

- (BOOL)CountData_sendAction:(SEL)action to:(id)target from:(id)sender forEvent:(UIEvent *)event {
    UIView *view = (UIView *)sender;
    NSMutableDictionary *prams = [[NSMutableDictionary alloc]init];
    //获取控件类型
    prams[@"$elementtype"] = view.elementType;
    [[SensorsAnalyticsSDK sharedInstance] track:@"$appclick" properties:prams];
    return  [self CountData_sendAction:action to:target from:sender forEvent:event];
}