iOS 全埋点-控件点击事件2

141 阅读3分钟

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

获取显示的文本

获取显示的文本,我们只需要针对特定的控件,调用相应的方法即可。我们以UIButton为例来介绍实现步骤。
首先声明一个UIView的分类UIView+TextContentData,然后在UIView的分类UIView+TextContentData添加 UIButton的分类
UIButton的分类。

UIView+TextContentData.h

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIView (TextContentData)
@property (nonatomic,copy,readonly) NSString *elementContent;
@end

@interface UIButton (TextContentData)

@end

NS_ASSUME_NONNULL_END

UIView+TextContentData.m

#import "UIView+TextContentData.h"

@implementation UIView (TextContentData)

- (NSString *)elementContent {
    return  nil;
}

@end

@implementation  UIButton (TextContentData)

- (NSString *)elementContent {
    return self.titleLabel.text;
}

@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;
    prams[@"element_content"] = view.elementContent;
    [[SensorsAnalyticsSDK sharedInstance] track:@"$appclick" properties:prams];
    return  [self CountData_sendAction:action to:target from:sender forEvent:event];
}

我们这里只是以UIButton为例,如果想扩充其他控件,直接添加对应控件的分类。

获取控件所属页面

如何知道UIView属于那个UIViewController,这个就需要借助UIResponder了。

UIApplicationUIViewControllerUIView类都是UIResponder的子类,在iOS应用程序中,UIApplication、 UIViewController、UIView类的对象也都是响应者,这些响应者会形成一个 响应者链。

一个完整的响应者链传递规则(顺序)大概如下: UIViewUIViewControllerUIWindowUIApplicationUIApplicationDelegate
如下图所示:

image.png

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

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

UIView+TextContentData.h

@interface UIView (TextContentData)

@property (nonatomic,copy,readonly) NSString *elementContent;
@property (nonatomic,strong,readonly) UIViewController *myViewController;

@end

UIView+TextContentData.m

#import "UIView+TextContentData.h"

@implementation UIView (TextContentData)

- (NSString *)elementContent {
    return  nil;
}

- (UIViewController *)myViewController {
    UIResponder *responder = self;
    while ((responder = [responder nextResponder])) {
        if ([responder isKindOfClass:[UIViewController class]]) {
            return (UIViewController *)responder;
        }
    }
    return  nil;
}

@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;
    //获取控件的内容
    prams[@"element_content"] = view.elementContent;
    //获取所属的页面
    UIViewController *vc = view.myViewController;
    prams[@"element_screen"] = NSStringFromClass(vc.class);
    [[SensorsAnalyticsSDK sharedInstance] track:@"$appclick" properties:prams];

    return  [self CountData_sendAction:action to:target from:sender forEvent:event];
}

更多控件

支持获取UISwitch控件文本信息

通过测试可以发现,UISwitch$AppClick事件没有$element_content属性。针对这个问题,可以解释为UISwitch控件本身就没有显示任何文本。 为了方便分析,针对获取UISwitch控件的文本信息,我们可以定一个简单的规则:当UISwitch控件的on属性为YES时,文本为“checked”;当 UISwitch控件的on属性为NO时,文本为“unchecked”。

解决方案
声明 UISwitch的分类

@implementation UISwitch (TextContentData)

- (NSString *)elementContent {
    return self.on ? @"checked":@"unchecked";
}

@end

滑动UISlider控件重复触发$AppClick事件解决方案

原因
我们在滑动UISlider控件过程中,系统会依次触发 UITouchPhaseBeganUITouchPhase-MovedUITouchPhaseMoved、……、 UITouchPhaseEnded事件,而每一个事件都会触发UIApplication- sendAction:to:from:forEvent:方法执行,从而触发$AppClick事件。
防止滑动UISlider重复响应,只有在UITouchPhaseEnded开始响应

 //防止滑动UISlider控制
    if(event.allTouches.anyObject.phase == UITouchPhaseEnded || [sender isKindOfClass:[UISwitch class]]) {
        [[SensorsAnalyticsSDK sharedInstance] track:@"$appclick" properties:prams];
    }