意甲赞助商:前端iOS打点统计的AOP技术实践

日期:2018-01-09 / 人气: / 来源:未知

  近期前端移动组因项目需求,意甲赞助商需要在用户行为上进行打点统计,但由于部分早期SDK在初始设计时并未考虑到日志记录这一功能,临时去变更代码所花费的成本也较高,所以架构组决定针对这一需求进行一次AOP开发实践,用面向切面统计来代替部分传统代码埋入打点。

  AOP的全称是Aspect Oriented Programming ,中文翻译是【面向切面编程】,与面向对象编程是两种不同的领域设计思想,AOP主要理念是针对业务处理过程中的切面进行提取,然后在切面上进行开发。

  由于Objective-C的运行时特性(Runtime),可以很方便的实现一些看起来非常Hack的行为,其中就包括Method Swizzling ,Method Swizzling主要应用就是来交换2个已经存在的方法,让方法A在真实运行中实际执行的是方法B,而方法B在运行中又是执行的是方法A。

  由上图方法的数据结构中可以看到一个完整的方法是主要由三部分组成,分别是SEL方法名、IMP 方法实现、Method_Type 方法参数和返回值,而@selector(insertObject:atIndex:) 这段代码的作用就是获取方法的SEL

  如果此时将SEL1指向IMP2、SEL2再指向IMP1,那么通过@selector(method1)拿到的实现就是IMP2,只要能完成此功能,那么就能实现方法的交换,

  这个就是Method Swizzling的原理,通过替换SEL对应的IMP来达到方法替换的目的

  // 开始交换,先直接往当前class中添加该方法,如果失败,说明方法已存在,直接交换即可(else逻辑)

  这样当一个ViewController开始展示时,会首先调用到drmSwizzled_viewDidAppear方法里面,再经由[self drmSwizzled_viewDidAppear]调回原来的viewDidAppear,然后我们就可以进行愉快的打点操作了,打点可以在原方法执行前或执行后都可以进行,也可以拿到对应的原方法的参数。

  如果只用上面的Method Swizzling方法的确已经可以完成在模块外部对模块内的方法进行打点,但缺点是对于关键方法可能每一个都需要进行Swizzle操作,如果方法量过多,其实接入成本也很高,然后我们再细化了需求,发现对于普通的用户操作,比如按钮点击、输入框文本变动其实可以用更快速的方式来监听。

  对于一个ViewController实例来说,必然会存在一个Root View,而拿到Root View之后,我们可以遍历它当前所有的subViews,层层递归下去,就可以拿到当前ViewController上面的所有包含页面控件。

  当我们拿到一个UIControl时,可以在外部给它再添加一个Touch Event事件、

  当我们拿到一个UITextField时,可以在外部给它再添加一个Text Changed事件、

  这样当我们遍历完所有控件时,我们也同步把页面所有的需要监听的控件增加的对应的方法,

  说完了原理,来看看具体的监听方法是如何添加到每一个控件上的(代码仅供参考):

  以上就可以快速的减少Swizzle的代码量,对于用户的实时行为,也能快速监听,初步猜测这也是GrowingIO前端数据无侵入埋点的主要逻辑。

  1.使用Method Swizzling可能会导致Debug困难,问题不易排查,但如果仅仅是swizzle UIViewController中的一个didAppear方法并不会带来太大的问题,多次swizzle也没有妨碍(前提是不会出现重名的方法,否则会陷入死循环),swizzle并不会增加太大开销。

  2.遍历当前页面控件会有极小的性能开销,此处也可以再优化,对于已经不需要进行递归的单一控件,就直接return掉就好。

  本文作者:余永凯,现就职于点融网工程部,iOS开发工程师一枚。爱好互联网,乐于创造新事物。返回搜狐,查看更多

作者:-1


现在致电 0898-68898911 OR 查看更多联系方式 →

Go To Top 回顶部