埋点是现在很多App中都需要用到的,这个问题可能每个人都能处理,但是怎样来减少埋点所带来的侵入性,怎样用更加简洁的方式来处理埋点问题,怎样减少误埋,如果上线了发现少埋了怎么办?下面是本文讨论的重点:
一、什么是埋点?埋点的作用是什么?
二、常规的处理方式是怎样的?
三、我们可以怎样优化?
四、怎样使用RunTime对其进行优化?
五、在实践中遇到了什么问题以及解决方案?
六、最理想的埋点是什么样的?
七、其中可能存在的问题是什么?
接下来将对其一一做以说明:
一、什么是埋点?埋点的作用是什么?
其实埋点也叫日志上报,其实就是根据需求上报一系列关于用户行为的数据,比如:用户点击了哪个按钮,用户浏览了哪个网站,用户在某个页面停留了多久等数据。这些数据对于运营来说很有用,他们可以用来分析某个功能开发的是不是合理,是不是因为某个地方的不合理而到导致了转化率的下降,从而对我们的App进行相应的改进,我们来看下某个第三方平台提供的埋点实例。
上图中说明了,某个时间对应的事件ID,以及针对这个事件需要关联的字段。下面是后台系统对某个埋点所做的数据统计:
这样我们就可以详细的分析出用户对于App的反馈,从而及时的修改我们的产品。
二、常规的埋点的处理方式是怎样的?
其实很简单,我们就在相应的事件里面加入相关的代码,给服务器上报数据不就得了。如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 |
// 这个一个按钮的响应事件 - (void)someButtonAction:(UIButton *)someButton{ // 该按钮需要处理的业务 [self upDateSomthing] // 开始埋点 // eid:事件id,sa:用户id, cI:当前时间 NSDictionary *upLoadDic = @{@"eid":@"311",@"sa":@"706976487532177",@"cI":@"2016-6-4 12:11:34"}; [ZHUpLoadManager upLoadWithDic:upLoadDic]; } |
这样一个埋点问题就解决了,单同时却隐藏着很多问题:1.这样每点击一个一下按钮就请求一次网络会不会出现性能问题?2.如果这样频繁的数据上报会不会消耗更多的用户流量?3.这样的代码能经受住需求的变更吗?比如字段变了,或者你把cI
看错了,应该是cl
。4.这样的代码会不会造成难以测试?5.这样的频繁上报会不会增加服务器端的压力?6.代码整洁吗?……(程序员的一个好习惯是:这个代码能否经受住需求的变更。)
三、我们可以怎样优化?
- 首先我们可以用一个类,来专门处理这些需要上报的埋点的字段,将这些字段作为常量,例如:
1 2 3 4 5 6 7 8 9 |
// LogManager.h extern NSString * const kLogEventKey; //事件id extern NSString * const kLogUserIdKey; //用户id extern NSString * const kLogOperationInterval; //操作时间 // LogManager.m NSString * const kLogEventKey = @"co"; //事件id NSString * const kLogUserIdKey = @"sa"; //用户id NSString * const kLogOperationInterval = @"cq"; //操作时间 |
- 对于用户id,当前时间,用户手机型号,手机品牌,等等与用户所在页面无关的内容,可以用统一的一个类进行处理,将其作为这个类的一个属性,使用
getter
方法将其相应的数值返回即可(对于恒定不变的可以使用懒加载)。 - 这样的数据传输策略是有问题的,每次点击都上报,可能一个面需要上报的地方很多,这就会造成很大的性能问题,我们可以先将需要上传的数据缓存起来,然后缓存够50条数据上报一次,或者每隔5分钟上报一次;
- 为了节省流量我们可以,1)将数据压缩之后再上报,可以参考我的另一篇文章;2)和服务端商量,用尽可能短的字段,如:
cityName = @"北京";
变为cn = @"北京";
3)尽量不要上传的频率过高,如第三点。 - 如何解决代码的整洁,易于测试的问题?请看下面。
四、怎样使用RunTime来进行优化?
我么能不能利用RunTime来给每一个Button的响应事件中添加一段代码,利用这段代码来进行埋点上报呢?或者进一步来说我们能不能给所有继承自UIControl的对象都添加这样一段代码呢?这样我们不是可以捕获所有的用户事件了吗?(其实答案是否定的,看第五条);这时我们可以利用Mehod Swizzle,或者叫方法注入
,或者叫hook
住了某个方法,听着挺玄乎,其实就是RunTime的一个API,这个API能够交换两个方法的实现。通过这个API,我们可以这样实现方法注入。如下图所示:
那么我们点击按钮系统会不会给每个按钮都执行一个统一的方法?然后我们往这个方法中嵌入响应的代码片段就可以了。答案是肯定的。我们可以往
1 |
- (void)sendAction:(SEL)action to:(nullable id)target forEvent:(nullable UIEvent *)event; |
这个方法里面嵌入相应的代码片段。我们可以这样:1.将互换方法实现的的这个方法放到一个工具类中,因为我们可能不止一处要用到这种方法。2.我们给UIControl添加一个Category,然后在里面调用这个工具类然后实现所插入的代码片段。这里我们既然可以得到target
还有action
,那么很多情况下我们就可以唯一确定这个埋点了,那么我们怎样从这么多的埋点中选出这个这个埋点呢?我们其实可以用字典和数组结合的方式将这些方法的target和方法的参数一一存起来,然后在嵌入的方法内部获取其对应的方法,以及其相应的,这个事先配置好的字典和数组的结合放在哪里比较合适呢?plist。下面就以最简单的形式展示这种思路:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 b3c290079094-81">81 82 83 84 85 怎样的?
三、我们可以怎样优化?四、怎样使用RunTime对其进行优化?五、在实践中遇到了什么问题以及解决方案?六、最理想的埋点是什么样的?七、其中可能存在的问题是什么?接下来将对其一一做以说明: 一、什么是埋点?埋点的作用是什么?其实埋点也叫日志上报,其实就是根据需求上报一系列关于用户行为的数据,比如:用户点击了哪个按钮,用户浏览了哪个网站,用户在某个页面停留了多久等数据。这些数据对于运营来说很有用,他们可以用来分析某个功能开发的是不是合理,是不是因为某个地方的不合理而到导致了转化率的下降,从而对我们的App进行相应的改进,我们来看下某个第三方平台提供的埋点实例。
上图中说明了,某个时间对应的事件ID,以及针对这个事件需要关联的字段。下面是后台系统对某个埋点所做的数据统计:
这样我们就可以详细的分析出用户对于App的反馈,从而及时的修改我们的产品。 二、常规的埋点的处理方式是怎样的?其实很简单,我们就在相应的事件里面加入相关的代码,给服务器上报数据不就得了。如下所示:
这样一个埋点问题就解决了,单同时却隐藏着很多问题:1.这样每点击一个一下按钮就请求一次网络会不会出现性能问题?2.如果这样频繁的数据上报会不会消耗更多的用户流量?3.这样的代码能经受住需求的变更吗?比如字段变了,或者你把 三、我们可以怎样优化?
四、怎样使用RunTime来进行优化?我么能不能利用RunTime来给每一个Button的响应事件中添加一段代码,利用这段代码来进行埋点上报呢?或者进一步来说我们能不能给所有继承自UIControl的对象都添加这样一段代码呢?这样我们不是可以捕获所有的用户事件了吗?(其实答案是否定的,看第五条);这时我们可以利用Mehod Swizzle,或者叫
那么我们点击按钮系统会不会给每个按钮都执行一个统一的方法?然后我们往这个方法中嵌入响应的代码片段就可以了。答案是肯定的。我们可以往
这个方法里面嵌入相应的代码片段。我们可以这样:1.将互换方法实现的的这个方法放到一个工具类中,因为我们可能不止一处要用到这种方法。2.我们给UIControl添加一个Category,然后在里面调用这个工具类然后实现所插入的代码片段。这里我们既然可以得到
|