CC_HookTrack可以做到
1、记录控制器进出的记录
2、记录动作点击触发的记录
3、预制记录,在请求接口时传输接口请求成功后的操作
有了这些,基本能清楚用户在app上做了什么操作。
使用时在启动处添加代码监听控制器
[UINavigationController hookUINavigationController_push];
[UINavigationController hookUINavigationController_pop];
添加代码抓取动作记录
[CC_HookTrack catchTrack];
可以在动作抓取后自行记录到本地,这个功能我暂时没有需求还没有添加。
已经上传到https://github.com/gwh111/bench_ios 支持pods
该模块既能绑定接口,即在请求接口时传给服务端,也可以记录到本地,隔段时间发送。我的业务找中使用第一种,因为大数据那边认为存下来定时发会丢失数据。其实友盟是用这种的。
业务中需要埋点统计各个模块,对于自定义埋点实在烦人,像这种有几十页,做完下版又换
所以无感知埋点可以减少人工活。
首先和往常一样,网上一顿搜,看看先人有什么解决方法。
这里有一篇http://www.cocoachina.com/ios/20180524/23500.html
iOS数据埋点统计方案(附Demo): 运行时Method Swizzling机制与AOP编程(面向切面编程)
这里用了Method Swizzling方法,抓取路径,它还有一个配置表,做这个表比较麻烦。
介绍一下CC_HookTrack中的一些函数
+ (void)catchTrack;
是抓取堆栈信息的函数,原理是在请求前抓取一次,来获得触发这次请求的路径。
使用了[NSThread callStackSymbols]来获取当前堆栈,后退两步就可以得到触发函数。
+ (void)willPopOfIndex:(int)index;
+ (void)willPushTo:(NSString *)toVC;
是预制函数,在接口请求成功前控制器是不会触发后退前进的,一般是请求成功后进入下一个页面,但是请求时要把参数带过去,如果这时候抓是抓不到之后的动作的,所以这种情况要预制,在接口请求里加入这个请求成功后的动作信息,来告诉大数据那边执行的操作。
最后,在控制器动作中主要用了method_exchangeImplementations函数,来提前获取信息。
作用就是在程序运行期间动态的给两个方法互换实现。
Method Swizzling也是iOS中AOP(面相切面编程)的一种实现方式,我们可以利用苹果这一特性来实现AOP编程。
更多参考https://www.jianshu.com/p/ff19c04b34d0
Method pushMethod = class_getInstanceMethod([self class], @selector(pushViewController:animated:));
Method hookMethod = class_getInstanceMethod([self class], @selector(hook_pushViewController:animated:));
method_exchangeImplementations(pushMethod, hookMethod);
我们也可以使用
来获得viewDidAppear调用情况,但是如果控制器重写了viewDidAppear,就无法触发,因为我们知道,如果在Catagory中重写一个方法,就会覆盖它的原有方法实现,会造成数据缺失,所以没有使用。
在hook_ViewDidAppear方法中又调用了[self hook_ViewDidAppear];,这难道不会产生递归调用吗?
不会,A、B两个方法已经互换,向A方法发送消息时执行的却是B方法,向B方法发送消息时执行的是A方法。
SEL : 类成员方法的指针,但不同于C语言中的函数指针,函数指针直接保存了方法的地址,但SEL只是方法编号。
IMP:一个函数指针,保存了方法的地址
获取方法编号
SEL methodId=@selector(func1);
执行编号对应方法
[self performSelector:methodIdwithObject:nil];
通过编号获取方法
NSString*methodName = NSStringFromSelector(methodId);
获得IMP使用
IMP methodPoint = [self methodForSelector:methodId];
methodPoint();