思路:我們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)targetaction:(SEL)actionforControlEvents:(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:selfaction:@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:targetaction:actionforControlEvents: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;}
}