iOS"无埋点"统计技术预研—收集篇
为了让公司领导和运营了解应用的某些方面的使用情况,如哪些功能点击量最高、APP版本分布情况、APP前后台使用时间等等,从而指导产品规划方向。如果不集成和依赖第三方库,就要探索如何实现自己的“无埋点”统计。本文属于技术预研篇。
1.埋点方案分类
埋点方案大体上可以归为三类:
(1)代码埋点,即在需要埋点的节点调用接口直接上传埋点数据,友盟、百度统计等第三方数据统计服务商大都采用这种方案;
(2)可视化埋点,即通过可视化工具配置采集节点,在前端自动解析配置并上报埋点数据,从而实现可视化“无痕埋点”, 代表方案Mixpanel;
(3)“无埋点”,它并不是真正的不需要埋点,而是前端自动采集全部事件并上报埋点数据,在后端数据计算时过滤出有用数据,代表方案GrowingIO。本文的部分思路也将借鉴这里。
2.收集数据分类
(1)通用全量事件收集
事件 | 描述 |
---|---|
冷启动事件 | App版本号、设备ID、渠道、内存使用情况等 |
前后台事件 | APP进入前台或后台 |
页面事件 | 页面显示或隐藏 |
控件点击事件 | 控件的点击量 |
位置事件 | 上报用户所在地理位置 |
其他事件 | 其他 |
3.“无埋点”收集实现要求
(1)现有代码改动尽量少
(2)降低耦合性
(3)全量收集
4.“无埋点”收集实现方案
根据上面的实现要求,我们很容易想到以下方案:
(1)AOP(Aspect-Oriented-Programming)即面向切面编程的思想,就是动态的在函数调用的前后插入数据收集的代码。将日志记录、性能统计、安全控制、异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,将它们独立到非业务逻辑的方法中,进而改 变这些行为的时候不影响业务逻辑的代码
(2)在 Objective-C 中的实现是基于 Runtime 特性的 Method Swizzling 来 hook 相应的方法
(3)开源框架:Aspects框架
5.Aspect原理
方法交换常用代码:
+ (void)load{static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{SEL origilaSEL = @selector(addTarget: action: forControlEvents:);
SEL hook_SEL = @selector(xw_addTarget: action: forControlEvents:);
//交换方法
Method origilalMethod = class_getInstanceMethod(self, origilaSEL);
Method hook_method = class_getInstanceMethod(self, hook_SEL);
class_addMethod(self,
origilaSEL,
class_getMethodImplementation(self, origilaSEL),
method_getTypeEncoding(origilalMethod));
class_addMethod(self,
hook_SEL,
class_getMethodImplementation(self, hook_SEL),
method_getTypeEncoding(hook_method));
method_exchangeImplementations(class_getInstanceMethod(self, origilaSEL), class_getInstanceMethod(self, hook_SEL));
});
Aspects是基于method swizzle的第三方库,用的就是AOP面向切面编程思想。Aspects要的是实现一个通用的IMP,任意方法任意参数都可通过这个IMP中转。
库的核心代码有两个方法:
//aspect_hookSelector:表示要拦截指定对象的方法。
//withOptions:是一个枚举类型,AspectPositionAfter/AspectPositionInstead/AspectPositionBefore 。
//usingBlock:就是拦截事件后执行的自定义方法。我们可以在这个block里面添加我们要执行的代码
+ (id)aspect_hookSelector:(SEL)selector
withOptions:(AspectOptions)options
usingBlock:(id)block
error:(NSError **)error;
/// Adds a block of code before/instead/after the current `selector` for a specific instance.
- (id)aspect_hookSelector:(SEL)selector
withOptions:(AspectOptions)options
usingBlock:(id)block
error:(NSError **)error;
Aspect源码主要用到了消息转发机制,有时间的可以研究下源码。下图展示的是消息转发机制的流程图:
文章图片
image.png 6.事件拦截示例
(1)点击事件拦截
事件 | hook的系统类 | hook的系统方法 |
---|---|---|
按钮的点击 | UIApplication | sendAction:to: from:forEvent: |
手势操作 | UIGestureRecognizer | initWithTarget:action: addTarget:action: |
列表点击 | UITableView和UICollectionView | setDelegate:、tableView:didSelectRowAtIndexPath:、collectionView:didSelectItemAtIndexPath:等 |
系统弹窗 | UIAlertView | setDelegate:、alertView:clickedButtonAtIndex: |
系统导航栏返回按钮 | UINavigationController | navigationBar:didPopItem: |
事件 | hook的系统类 | hook的系统方法 |
---|---|---|
页面事件 | UIVIewController | viewDidLoad 、viewWillAppear: 、viewDidAppear: 、viewWillDisappear:等生命周期方法: |
文章图片
代码示例.png 7.viewPath
为了对 某个页面的某个 view 进行数据收集,view需要一个唯一标识。视图结构可以看成是一颗树(viewTree)。
规定:在 viewTree 中,由一个 view 到根节点之间的每个节点的名称与深度(index)共同组成的信息,构成了此 view 的viewPath。
文章图片
viewPath示例.png
文章图片
growingIO xpath.png
参考文章: https://www.jianshu.com/p/69ce01e15042 【iOS"无埋点"统计技术预研—收集篇】
推荐阅读
- 2020-04-07vue中Axios的封装和API接口的管理
- iOS中的Block
- 杭电oj——2030汉字统计
- 概率论/统计学|随机变量 的 分布函数 与 概率密度函数 的区别
- 记录iOS生成分享图片的一些问题,根据UIView生成固定尺寸的分享图片
- 2019-08-29|2019-08-29 iOS13适配那点事
- Hacking|Hacking with iOS: SwiftUI Edition - SnowSeeker 项目(一)
- iOS面试题--基础
- 临床统计学学习日志
- 接口|axios接口报错-参数类型错误解决