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;
}
}