当前位置: 首页 > article >正文

iOS 实现UIButton自动化点击埋点

思路:我们HOOK UIControl的 addtarget:action:forControlEvents方法,交换UIControl的 addtarget:action:forControlEvents
方法的实现, 在交换的方法中添加原来响应的同时,再添加一个埋点响应,该响应方法实现了点击埋点操作,同时要添加一个标记为,记录我们添加过
点击埋点响应了,防止外部再次添加响应的时候,我们这里重复添加埋点响应,同时,还要hook removeTarget:action:forControlEvents方法,在该方法中记录我们绑定的点击处理次数,当次数大于0时,进行埋点上报

一下是我们的实现代码

static const void *lbmonitorActionNameKey = "monitorActionNameKey";
static const void *lbSenderAction = "lbSenderAction";
static const void *lbTabButtonId = "lbTabButtonId";
static const void *lbClickActionCounts = "lbClickActionCounts";

@implementation UIControl (LB)
@dynamic actionName;

+ (void)load
{
    lbinstanceMethod_fastExchangeImplementations([self class], @selector(addTarget:action:forControlEvents:), [self class], @selector(lbtracker_addCagegoryTarget:action:forControlEvents:));
    instanceMethod_fastExchangeImplementations([self class], @selector(removeTarget:action:forControlEvents:), [self class], @selector(lbtracker_removeCagegoryTarget:action:forControlEvents:));
}

- (void)lbtracker_addCagegoryTarget:(id)target
                               action:(SEL)action
                     forControlEvents:(UIControlEvents)controlEvents
{
    // 自动化埋点:只针对”点击“进行埋点,一次点击一次上报,且先埋点后业务。
    if ([self isKindOfClass:[UITextField class]] == NO && controlEvents == UIControlEventTouchUpInside) {
        // 避免:业务添加多次点击回调时,触发多次埋点或者点击处理顺序错乱。
        NSNumber *hookClickMethod = objc_getAssociatedObject(self, "lb_track_click");
        NSLog(@"哈哈哈哈哈这里的hookClickMethod%@ %@", self, hookClickMethod);
        if (!hookClickMethod) {
            objc_setAssociatedObject(self, "lb_track_click", @(1), OBJC_ASSOCIATION_RETAIN);
            [self setSenderAction:NSStringFromSelector(action)];
            [self autotracker_addCagegoryTarget:self
                                         action:@selector(autotracker_monitorAction:forEvent:)
                               forControlEvents:controlEvents];
        }
        
        // 记录控件绑定点击处理次数,当次数大于0时,进行点击埋点上报。
        NSArray *actionNames = [self actionsForTarget:target forControlEvent:controlEvents];
        NSLog(@"哈哈哈哈哈这里这里的数量数量%@ %@", actionNames, NSStringFromSelector(action));
        if (actionNames.count == 0 || ![actionNames containsObject:NSStringFromSelector(action)]) {
            NSLog(@"这里的原始数量%ld %@", [self lbtracker_clickActionCounts], self);
            [self setAutotracker_clickActionCounts:[self autotracker_clickActionCounts] + 1];
        }
    }
    
    [self autotracker_addCagegoryTarget:target
                                 action:action
                       forControlEvents:controlEvents];
}

- (void)lbtracker_removeCagegoryTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents
{
    // 减少控件绑定点击处理次数,当次数大于0时,进行点击埋点上报。
    NSArray *actionNames = [self actionsForTarget:target forControlEvent:controlEvents];
    if (actionNames.count > 0 && [actionNames containsObject:NSStringFromSelector(action)]) {
        APLogInfo(@"AutoTrack", @"Click %@ remove T", NSStringFromSelector(action));
        [self setlbTracker_clickActionCounts:[self lbtracker_clickActionCounts] - 1];
    }
    [self lbtracker_removeCagegoryTarget:target action:action forControlEvents:controlEvents];
}

- (void)lbtracker_monitorAction:(UIControl *)sender forEvent:(UIEvent *)event
{
    LBLog(@"lbTrack", @"Click %@ counts = %@", self.senderAction, @([self lbtracker_clickActionCounts]));
    if (self.skipTrack || 0 == [self lbtracker_clickActionCounts]) {
        return;
    }
    
    [self lbtracker_parseClickPoint:event];
  	//执行埋点操作
}

- (NSString *)actionName {
    return objc_getAssociatedObject(self, monitorActionNameKey);
}

- (void)setActionName:(NSString *)monitorActionName{
    objc_setAssociatedObject(self, monitorActionNameKey,
                             monitorActionName,
                             OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSString *)senderAction {
    return objc_getAssociatedObject(self, KSenderAction);
}

- (void)setSenderAction:(NSString *)senderAction{
    objc_setAssociatedObject(self, KSenderAction,
                             senderAction,
                             OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSString *)tabButtonId {
    return objc_getAssociatedObject(self, KTabButtonId);
}

- (void)setTabButtonId:(NSString *)tabButtonId {
    objc_setAssociatedObject(self, KTabButtonId, tabButtonId, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSInteger)autotracker_clickActionCounts
{
    NSNumber *counts = objc_getAssociatedObject(self, LBClickActionCounts);
    return [counts integerValue];
}

- (void)setLBtracker_clickActionCounts:(NSInteger)count
{
    NSLog(@"这里的数量这里的数量%ld", count);
    objc_setAssociatedObject(self, LBClickActionCounts, @(count), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}


- (void)lbtracker_parseClickPoint:(UIEvent *)event
{
    // 获取点击位置坐标
    CGPoint clickPoint;
    UITouch *touch = [event touchesForView:self].anyObject;
    if (touch) {
        clickPoint = [touch locationInView:self];
    }
    
    if ([self respondsToSelector:@selector(lbLogModel_auk)]) {
        LBLogModel *model = [self performSelector:@selector(lbLogModel_auk)];
        model.clickPoint = clickPoint;
    }
}

http://www.kler.cn/a/568625.html

相关文章:

  • 从人口焦虑到科技破局:新生人口减少不再是难题,未来社会已悄然蜕变
  • Mysql的索引失效
  • 数据库拓展操作
  • Vim 常用快捷键大全:跳转、编辑、查找替换全解析
  • 委托者模式(掌握设计模式的核心之一)
  • 华为手机自助维修的方法
  • Memcached监控本机内存(比redis速度更快)
  • C++编程指南21 - 线程detach后其注意变量的生命周期
  • leetcode第77题组合
  • next.js-学习4
  • 蓝桥杯 6.数学
  • 基于springboot+vue的线上考试系统的设计与实现
  • 在 Ubuntu 下通过 Docker 部署 Caddy 和 PHP-FPM 服务器
  • Java—锁—等待唤醒机制
  • 随机树算法 自动驾驶汽车的路径规划 静态障碍物(Matlab)
  • thinkphp6-使用psubscribe进行redis的注意callback中使用redis
  • 《Python实战进阶》No 11:微服务架构设计与 Python 实现
  • 字符串的最大公因子<枚举>
  • C语言学习笔记-初阶(23)函数详解
  • QT——c++界面编程库