七步实现列表点击事件的采集

图片

一、前言

在 iOS 全埋点采集中,cell 点击事件采集通常是指对 UITableViewCell 和 UICollectionViewCell 的用户点击行为进行采集。

cell 的点击是通过协议中的方法实现的,因此我们对 UITableView 的协议方法 - tableView:didSelectRowAtIndexPath: 和 UICollectionView 的协议方法 - collectionView:didSelectItemAtIndexPath: 进行 hook 即可达到采集的目的。

在 iOS 中对方法进行 hook,最简单的方式就是通过 Method Swizzling[1] 交换方法的 IMP,但这种方式无法完全适应 cell 点击事件采集,缺陷如下:

  • Method Swizzling 的代码需要确保只执行一次,但代理对象可能会被设置多次;

  • 代理对象存在子类继承时,需要区分子类是否重写了要交换的方法;

  • 诸如 RxSwift、Texture 等三方库使用消息转发时,则无法进行方法交换。

正是因为存在上述缺陷,我们不得不寻找其他 hook 方案。

二、方案

2.1 概述

Method Swizzling 交换方法是对整个类及其子类都生效的,那么是否存在一种 hook 方案只作用于当前的代理对象呢?答案是肯定的。

我们的采集方案是在获取代理对象后,基于该代理对象的类,创建一个独一无二的子类,该子类继承自原来的类。在子类中对 - tableView:didSelectRowAtIndexPath: 和 - collectionView:didSelectItemAtIndexPath: 方法进行重写,然后将代理对象的 isa 指针指向新建的子类,最后只需要在该代理对象释放的同时释放新建的子类即可。

这样就能够对 cell 点击事件进行采集,并且没有对点击方法进行交换,也就不存在 Method Swizzling 的相关问题。

2.2 原理

hook 原理如图 2-1 所示,在我们更改了代理对象的 isa 指针后,当用户点击 cell 时系统会优先调用我们子类重写的 - tableView:didSelectRowAtIndexPath: 或 - collectionView:didSelectItemAtIndexPath: 方法。此时可以进行事件采集,然后调用父类中的方法,完成消息的转发。

图片

图 2-1 代理对象的 isa 指针变化

2.3  实现

2.3.1. 获取代理

由于获取代理对象仅需要 hook UITableView 和 UICollectionView 的 - setDelegate: 方法,要 hook 的类是已知的,因此我们可以使用 Method Swizzling:

SEL selector = NSSelectorFromString(@"sensorsdata_setDelegate:");[UITableView sa_swizzleMethod:@selector(setDelegate:) withMethod:selector error:NULL];[UICollectionView sa_swizzleMethod:@selector(setDelegate:) withMethod:selector error:NULL];

在 - sensorsdata_setDelegate: 方法中即可获取代理对象:​​​​​​​

- (void)sensorsdata_setDelegate:(id <UITableViewDelegate>)delegate {
      [self sensorsdata_setDelegate:delegate];     if (delegate == nil) {
          return;    }    // 使用委托类去 hook 点击事件方法    [SADelegateProxy proxyWithDelegate:delegate];}

2.3.2. 创建子类

动态创建子类,需要使用 runtime[2] 的 objc_allocateClassPair 接口,定义如下:​​​​​​​

OBJC_EXPORT Class _Nullableobjc_allocateClassPair(Class _Nullable superclass, const char * _Nonnull name,          
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值