无侵入埋点思路

思路图

无侵入埋点思路图.png

思路解析:利用Method Swizzling(黑魔法)实现埋点统计的无侵入实现。

步骤如下

1.调用class_addMethod为需要hook的类增加新方法,用新的SEL指向原有的方法实现IMP;
2.调用method_setImplementation为原有Method设置新的IMP;
3.在新的IMP中,调用新的SEL,实现原方法的IMP,并收集对象,参数等信息传入埋点业务模块;
4.在埋点业务模块中,加入埋点逻辑。

比如我们可以实现,收集用户crash前的操作,功能:
分析:用户主要行为就是点击,所以我们主要收集的就是用户crash前的点击事件,也就是action-target;我们知道对于一个给定的事件,UIControl会调用sendAction:to:forEvent:来将行为转发到UIApplication对象,再由UIApplication对象调用其sendAction:to:fromSender:forEvent:方法来将消息转发到指定target上,而如果我们没有指定target,则会将事件分发到事件响应者链上第一个想处理消息的对象上。我们现在主要收集有指定target响应的action。

我们可以hook UIApplication对象的sendAction:to:fromSender:forEvent:方法,收集信息。

代码如下:

@interface UIApplication (HLCHook)
+ (void)hookUIApplication;
@end

@implementation UIApplication (HLCHook)
+ (void)hookUIApplication
{
Method controlMethod = class_getInstanceMethod([UIApplication class], @selector(sendAction:to:from:forEvent:));
Method hookMethod = class_getInstanceMethod([self class], @selector(hook_sendAction:to:from:forEvent:));
method_exchangeImplementations(controlMethod, hookMethod);
}


- (BOOL)hook_sendAction:(SEL)action to:(nullable id)target from:(nullable id)sender forEvent:(nullable UIEvent *)event;
{
NSString *actionDetailInfo = [NSString stringWithFormat:@" %@ - %@ - %@", NSStringFromClass([target class]), NSStringFromClass([sender class]), NSStringFromSelector(action)];
NSLog(@"%@", actionDetailInfo);
return [self hook_sendAction:action to:target from:sender forEvent:event];
}
@end

至此,核心功能已经实现,只需要在UIApplication的代理方法application:didFinishLaunchingWithOptions:中添加[UIApplication hookUIApplication];方法,即可实现。

同理可得埋点UINavigationController的push和pop,一个页面的停留时间,都可以用hook方式实现

总结:

1.hook方式非常强大,几乎可以截取任何用户想截取的消息事件,但是,每次触发hook,必然存在置换IMP整个过程,频繁的置换IMP必然会影响到应用及手机资源的消耗,不到非不得已,建议少用。
2.需要知道什么时候用hook方式来埋点。如果十个页面,只有一两个页面需要埋点,是不需要用hook方式来埋点的。没有最好的方法,只有最合适的方法。


觉得有用,请帮忙点亮红心


Better Late Than Never!
努力是为了当机会来临时不会错失机会。
共勉!

你可能感兴趣的:(无侵入埋点思路)