前言
所谓埋点就是在应用中特定的流程收集一些信息,用来跟踪应用使用的状况,随着现在的互联网的越来越便利,然后精准分析用户数据变成为一种新的大趋势,用户在这个页面停留时间、点击按钮、浏览内容、手机型号、网络环境等等等都可以进行统计
要做数据分析不外乎就两种,一种服务器通过接口调用情况统计,另外一种就是前端埋点统计,当然前端埋点统计可以更精准的统计更多数据信息~
埋点方案
大致分为三种,代码埋点、可视化埋点,无埋点
第一种:代码埋点
很简单明了就是在需要统计埋点的控制器和按钮事件等地方做好埋点处理
第二种:可视化埋点
根据标识来识别每一个事件, 针对指定的事件进行取参埋点。而事件的标识与参数信息都写在配置表中,通过动态下发配置表来实现埋点统计
第三种:无埋点
无埋点是指开发人员集成采集 SDK 后,SDK 便直接开始捕捉和监测用户在应用里的所有行为,并全部上报,不需要开发人员添加额外代码
想关于这三种的介绍,网上资料一大堆,感兴趣的朋友可以自己去搜索看看,
美团点评前端无痕埋点实践
实战处理
统计用户浏览页面
下面是一个很简单的统计用户浏览埋点方式,其实就是利用Runtime交换viewDidLoad
方法
+ (void)load{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ kMethodSwizzling(self.class, @selector(viewDidLoad), @selector(kj_viewDidLoad)); }); } - (void)kj_viewDidLoad{ [self kj_viewDidLoad]; NSString *clazz = NSStringFromClass([self class]); NSDictionary *dict = @{ @"userid":KJHookInfo.shared.userid, @"viewController":clazz }; NSString *parameter = dict.jsonString.kj_aesEncryptKey(@"key"); //TODO:上传数据 }
统计指定页面
升级一下,浏览指定控制器埋点,通过接口动态返回需要统计的界面控制器,储存在hookViewControllers
,然后统计
- (void)kj_viewDidLoad{ [self kj_viewDidLoad]; NSString *clazz = NSStringFromClass([self class]); BOOL isHook = ({ BOOL isHook = NO; for (NSString *name in KJHookInfo.shared.hookViewControllers) { if ([name isEqualToString:clazz]) { isHook = YES; break; } } isHook; }); if (isHook) { NSDictionary *dict = @{ @"userid":KJHookInfo.shared.userid, @"viewController":clazz }; NSString *parameter = dict.jsonString.kj_aesEncryptKey(@"key"); //TODO:上传数据 } }
统计用户页面浏览时长
再介绍一个统计页面停留时长的埋点处理 简单讲就是交换viewWillAppear:
和viewDidDisappear:
+ (void)load{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ kMethodSwizzling(self.class, @selector(viewWillAppear:), @selector(kj_viewWillAppear:)); kMethodSwizzling(self.class, @selector(viewDidDisappear:), @selector(kj_viewDidDisappear:)); }); } - (void)kj_viewWillAppear:(BOOL)animated{ [self kj_viewWillAppear: animated]; // 记录进入时间 KJHookInfo.shared.time = CFAbsoluteTimeGetCurrent(); } - (void)kj_viewDidDisappear:(BOOL)animated{ [self kj_viewDidDisappear: animated]; NSString *clazz = NSStringFromClass([self class]); BOOL isHook = ({ BOOL isHook = NO; for (NSString *name in KJHookInfo.shared.hookViewControllers) { if ([name isEqualToString:clazz]) { isHook = YES; break; } } isHook; }); if (isHook) { NSTimeInterval time = CFAbsoluteTimeGetCurrent() - KJHookInfo.shared.time; NSDictionary *dict = @{ @"userid":KJHookInfo.shared.userid, @"time":time, @"viewController":clazz }; NSString *parameter = dict.jsonString.kj_aesEncryptKey(@"key"); //TODO:上传数据 } }
用户点击事件
大多数可点击UI控件都是基于UIControl,核心还是交互方法sendAction:to:forEvent:
,下面提供一种统计到某个具体页面的按钮
@implementation UIControl (KJHook) + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ kMethodSwizzling(self.class, @selector(sendAction:to:forEvent:), @selector(kj_sendAction:to:forEvent:)); }); } - (void)kj_sendAction:(SEL)action to:(nullable id)target forEvent:(nullable UIEvent *)event { [self kj_sendAction:action to:target forEvent:event]; _weakself; kGCD_async(^{ if ([NSStringFromClass(weakself.class) isEqualToString:@"UIButton"]) { void (^kDealButton)(NSString *) = ^(NSString *clazz){ NSDictionary *dict = @{ @"userid":@"userid", @"centerX":[NSString stringWithFormat:@"%.2f",weakself.centerX], @"centerY":[NSString stringWithFormat:@"%.2f",weakself.centerY], @"viewController":clazz }; NSString *parameter = dict.jsonString.kj_aesEncryptKey(@"key"); NSLog(@"%@",parameter); //TODO:上传数据 }; kGCD_main(^{ kDealButton(NSStringFromClass([[target viewController] class])); }); } }); } @end
这里如果想更准确,还可给每个按钮编tag值,当然这个工程量就比较大,这边只是提供思路,具体怎么做示实际情况为准
这里值得一提的就是,在交换方法的时候,一定要全局查询是否命名冲突(有没有方法名重复),否则可能会出现你埋点的方法压根不执行,原理可以参考我另外一篇关于Category介绍的文章iOS Category类别的使用及工具封装
埋点后续处理
接口数据上传
通常我们埋好点之后,采取的方式都是调用服务器的一个指定接口,但是有一个缺陷就是在高峰期时刻访问量会非常巨大,就有超出服务器范围的可能
图片访问式统计
scheme:https host:upload-images.jianshu.io path:/upload_images/1933747-82138031f05852ab.gif query:tR8XBkv3BaBjjEeck9VbeiZauP73MdXWlhvmUq+BAFY=
正常我们访问一张图片,其实只需要scheme://
+ host
+ path
三部分就可以正常访问
但是下面这张格式组成 scheme://
+ host
+ path
+ ?
+ query
也是可以正常访问
所以我们可以将埋点信息放在query
当中,然后只需要统计这张图片的访问记录就可以简单快捷的拿到埋点的内容
带宽考虑:图片我们也可以采用1像素
的图片,这样也不会怎么占用服务器的带宽
安全考虑:同样我们也可以将需要的参数加密
NSDictionary *dict = @{@"app":@"appname"}; NSString *parameter = dict.jsonString.kj_aesEncryptKey(@"key");
后续思考
我们都知道访问得到的图片都是data数据,那么我们是否也可以把我们想要反馈给客户端的数据藏于data当中解析呢?
那么大家还有什么比较优秀的埋点方式呢?欢迎分享,谢谢~