第47月第21天 iOS 无痕埋点解决方案
1.
生成 Target-Action 埋点的唯一 ID
Target-Action 是手势和 UIControl 的回调,一般使用如下代码
-[UIControl addTarget:action:events:]
-[UIGestureRecognizer initWithTarget:action:]
我们 hook 了
-[UIControl addTarget:action:events:]
方法,创建了一个Action
对象作为附属对象,和实际的 target 一同添加到 UIControl 中。当 UIControl 触发了事件,就会同时向业务对象和Action
对象发送消息,从而产生埋点。故我们可以在-[UIControl addTarget:action:events:]
方法中获取到 target、action、event。还能从-[Action action:]
方法中获取实时埋点数据。
采集
-[UIControl addTarget:action:events:]
在此方法中,我们可以获取到 UIControl 类名,target 对象,action 方法名,events 事件名。由于后三个数据在下面的方法中无法获取,所以会记录后三个数据到 Action 对象中,供 Action 对象在触发下面的方法时获取对应数据:
// In UIControl+Hook.m
- (void)hook_addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)events {
// Call origin method
[self hook_addTarget:target action:action forControlEvents:events];
// Create Action object
MyTargetAction *action = [[MyTargetAction alloc] init];
action.targetName = NSStringFromClass([target class]);
action.action = NSStringFromSelector(action);
action.events = events;
// Add Action object
[self hook_addTarget:action action:@selector(action:) forControlEvents:events];
}
-[Action action:]
此方法是实际埋点执行的方法,由于此方法只能获取 self(Action 对象)和 sender(UIControl 对象),故实际埋点数据还是依赖前一个方法临时保存的数据。
此时我们可以在方法中构成埋点数据。
- self(Action 对象)
- sender(UIControl 对象)
- VC(可以根据 UIControl 获取所在 VC)
- self.targetName(target 类名)
- self.action(action 方法名)
- self.events(events 值)
拼接事件
Action 对象
此对象是 SDK 内部对象,无任何信息
sender
控件对象,大部分按钮不会继承,所以也不会有信息。
self.targetName
响应者类名,此类一般为 VC 的类名,或者某个 View 的类名,故此信息可用于拼接。
self.action
响应方法名,于前一个相同,但不同事件一般会有不同方法回调,所以方法名也可以作为唯一事件 ID。
self.events
事件类型,不同控件不同事件,但按钮基本为 UIControlEventsTouchUpInside
,如果要区分不同控件则可以加入,本文只考虑按钮情况。故不加入此信息
最终事件 ID 如下:
VCClassName
#TargetClassName
#ActionName
// In MyTargetAction.m
- (void)action:(UIControl *)sender {
NSString *event_code = ({
NSString *viewController = ({
UIResponder *responder = sender;
while (responder) {
responder = responder.nextResponder;
if ([responder isKindOfClass:[UIViewController class]]) {
break;
} else if ([responder isKindeOfClass:[UIWindow class]]) {
break;
}
}
NSStringFromClass([responder class]);
});
[NSString stringWithFormat:@"%@#%@#%@", viewController, self.targetName, self.actionName];
});
[Tracker trackEvent:event_code];
}
举例:
UIViewController#UIViewController#onClick:
UIViewController#MenuItemCell#onClickAdd: