最近为了响应公司要求,需要对APP进行埋点来观察用户的使用行为而进行了一次对埋点方案的学习。通过学习了解到了三种埋点方案
- 代码埋点:通过手写代码的方式进行埋点,能精准的在需要埋点的地方插入埋点代码。但工作量大,埋点代码遍布整个项目,后期维护难度很大。
- 可视化埋点:将埋点增加和修改的工作可视化了,提升了增加和维护埋点的体验。
- 无埋点:可以理解为全埋点,埋点代码高度聚合,容易管理和维护,适合大量通用的埋点需求。
公司的需求是记录用户打开APP后到底进入了哪些界面,点击了哪些按钮,哪些功能是使用的比较多的,哪些是僵尸功能。结合三种埋点方案的特性,我最后选择了无埋点的方案。
人善,话不多,拿起键盘就开干。
磨刀不误砍柴工,我们现在需要实现一个运行时替换方法的类KSwizzling,具体代码如下
#import "KSwizzling.h"
#import <objc/runtime.h>
@implementation KSwizzling
+ (void)methodSwizzling:(Class)class originalSelector:(SEL)originalSelector swizzlingSelector:(SEL)swizzlingSelector {
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzlingMethod = class_getInstanceMethod(class, swizzlingSelector);
if (class_addMethod(class, originalSelector, method_getImplementation(swizzlingMethod), method_getTypeEncoding(swizzlingMethod))) {
//进行方法的替换
class_replaceMethod(class, swizzlingSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}else {
//交换IMP指针
method_exchangeImplementations(originalMethod, swizzlingMethod);
}
}
@end
有了这个核心的类我们就能很方便的开发后面的需求。
首先我需要记录的是用户在使用的过程中进入了哪些界面。所以我需要在- (void)viewDidLoad
这个方法里面进行埋点。我的实现方法是为UIViewController添加一个分类,在+ (void)load
方法里面交换- (void)viewDidLoad
的实现,具体代码如下
#import "UIViewController+Logging.h"
#import "KSwizzling.h"
@implementation UIViewController (Logging)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[KSwizzling methodSwizzling:self originalSelector:@selector(viewDidLoad) swizzlingSelector:@selector(swizzlingViewDidLoad)];
});
}
- (void)swizzlingViewDidLoad {
[self swizzlingViewDidLoad];
//在这里写埋点代码
<#code#>
}
@end
到这里我们就实现了对ViewController的埋点,接下来就是对按钮点击事件的埋点,原理其实是一样的。我们也为UIButton添加一个分类,只不过在+ (void)load
方法里面交换的是- (void)sendAction:(SEL)action to:(nullable id)target forEvent:(nullable UIEvent *)event
这个方法的实现,具体代码如下
#import "UIButton+Logging.h"
#import "KSwizzling.h"
@implementation UIButton (Logging)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[KSwizzling methodSwizzling:self originalSelector:@selector(sendAction:to:forEvent:) swizzlingSelector:@selector(swizzlingSendAction:to:forEvent:)];
});
}
- (void)swizzlingSendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
[self swizzlingSendAction:action to:target forEvent:event];
//在这里写埋点代码
<#code#>
}
@end
最后我们也实现了按钮事件的埋点