数据埋点的思考—Swift协议篇

2019-02-12

春节假期结束,开工前,总结下年前所做的数据埋点的那些事。

要做啥

随着公司业务的发展,需要对用户数据行为进行更深入的定制化,时时性及准确性要求更高。之前所用的第三方,友盟统计,GrowingIO等相继无法满足,因此CPO一声令下:冲啊!(做自己的数据埋点系统)。那就冲吧~~。所做埋点的地方无外乎:页面统计(进出,停留时间),用户操作统计(点击,滑动,登录登出),以及特定按钮的上报等用户行为。那么知道了具体需求,下面就谈谈实现的思路。

实现思路

要自己实现数据埋点,该怎么做呢?首先,要确定是使用手动埋点,还是所谓的“无痕埋点”。

无痕埋点

GrowingIO就是所谓的无痕埋点。为什么我说是所谓的呢。它无非是前端自动采集全部事件并上报埋点数据,在后端数据计算时过滤出有用数据。而且在集成的过程中你还是需要手动写些东西的。它运用了Runtime运行时方法交换,以及前后端数据埋点相互关联来实现所谓的无痕。(说到这里,可能有的小伙伴会说,你不是要讲Swift的协议吗,怎么又扯到OC了呢。先别急,我这只是在交代下我的思考过程)起初我也是想通过runtime来做此次需求的(由于本公司项目主要用OC开发),但是在实现的过程中,发现由于之前引入了GrowingIO,导致控制器等好多类都已经被动态修改类名,加入了GrowingIO的标示,无法准确获取目标类。而且CPO还要求继续使用GrowingIO,因此通过运行时来做所谓的无痕埋点行不通。那就只能考虑手动埋点了。

手动埋点

手动埋点怎么手动,怎么埋呢?这又需要一番思考。我想到了以下方法:

(1)继承:继承多数情况下是创建一个基类,在基类里实现公共方法,子类继承基类来共享方法,并且子类也可重写基类方法来定制。但缺点明显,对于已经存在的类,需手动修改继承对象,不够灵活,且继承对象不唯一,不支持多继承,工作量太过繁琐。

(2)分类:相比继承有其优势,可以在不改变类本身前提下,给其拓展方法。但缺点是分类重写了父类方法后,父类方法不在调用。这可能又会想到重写分类的+ (void)load 方法,使用Method Swizzling来实现交换方法,但前面已经提到runtime对我来说是行不通的。

(3)埋点类:可以创建一个埋点类,它可以为单例的形式存在。再此类中声明实现埋点的方法,外部统一调用此类就行埋点。看似这是最简单的思路,但仔细想想又觉得不太合适。首先需要埋点的类很多,你不得不在此埋点类里引入过多头文件,其次涉及到埋点上报,此类会包含各种上报请求及处理逻辑,使得此类过于臃肿难看。给人一种不专业的感觉。

(4)协议

OC中的协议:实现思路很简单,创建一个埋点协议,声明需要遵守的协议方法,在需要实现埋点的类里接受协议,实现协议方法即可。这样就看起来比较专业,需要埋点的地方就接受协议,实现协议就好。但和Swift里的协议比起来,OC的协议显得就弱小许多,下面就是重头戏Swift中的协议。

Swift中的协议:Swift 的协议和 Objective-C 的协议不同。Swift 协议可以被用作代理,也可以让你对接口进行抽象 (比如 IteratorProtocol 和 Sequence)。它们和 Objective-C 协议的最大不同在于我们可以让结构体和枚举类型满足协议。除此之外,Swift 协议还可以有关联类型。我们还可以通过协议扩展的方式为协议添加方法实现以及协议的默认实现。这就是Swift协议的强大之处,我们可以通过 extension 为协议添加拓展,并可以实现默认协议,而无需重复默认的操作。对于埋点,考虑到控制器入屏出屏,时间停留,以及按钮点击操作的上报数据格式基本固定,我们完全可以定制一套协议的默认实现来简化代码。在需要定制埋点的地方,重新实现协议即可。对于事件标示及控件ID我们可以事先于后台定制一套映射关系,前段以配置文件的形式存在本地,需要时直接读取配置文件即可。当然Swift中的协议还有很多强大的功能,这里只提到了我在埋点里涉及到东西。

以上就是我对数据埋点的思考与小结,由于本人学识浅薄,考虑不妥之处还请大神指出。