iOS 实现UIButton自动化点击埋点

思路:我们HOOK UIControl的 addtarget:action:forControlEvents方法,交换UIControl的 addtarget:action:forControlEvents
方法的实现, 在交换的方法中添加原来响应的同时,再添加一个埋点响应,该响应方法实现了点击埋点操作,同时要添加一个标记为,记录我们添加过
点击埋点响应了,防止外部再次添加响应的时候,我们这里重复添加埋点响应,同时,还要hook removeTarget:action:forControlEvents方法,在该方法中记录我们绑定的点击处理次数,当次数大于0时,进行埋点上报

一下是我们的实现代码

static const void *lbmonitorActionNameKey = "monitorActionNameKey";
static const void *lbSenderAction = "lbSenderAction";
static const void *lbTabButtonId = "lbTabButtonId";
static const void *lbClickActionCounts = "lbClickActionCounts";

@implementation UIControl (LB)
@dynamic actionName;

+ (void)load
{
    lbinstanceMethod_fastExchangeImplementations([self class], @selector(addTarget:action:forControlEvents:), [self class], @selector(lbtracker_addCagegoryTarget:action:forControlEvents:));
    instanceMethod_fastExchangeImplementations([self class], @selector(removeTarget:action:forControlEvents:), [self class], @selector(lbtracker_removeCagegoryTarget:action:forControlEvents:));
}

- (void)lbtracker_addCagegoryTarget:(id)target
                               action:(SEL)action
                     forControlEvents:(UIControlEvents)controlEvents
{
    // 自动化埋点:只针对”点击“进行埋点,一次点击一次上报,且先埋点后业务。
    if ([self isKindOfClass:[UITextField class]] == NO && controlEvents == UIControlEventTouchUpInside) {
        // 避免:业务添加多次点击回调时,触发多次埋点或者点击处理顺序错乱。
        NSNumber *hookClickMethod = objc_getAssociatedObject(self, "lb_track_click");
        NSLog(@"哈哈哈哈哈这里的hookClickMethod%@ %@", self, hookClickMethod);
        if (!hookClickMethod) {
            objc_setAssociatedObject(self, "lb_track_click", @(1), OBJC_ASSOCIATION_RETAIN);
            [self setSenderAction:NSStringFromSelector(action)];
            [self autotracker_addCagegoryTarget:self
                                         action:@selector(autotracker_monitorAction:forEvent:)
                               forControlEvents:controlEvents];
        }
        
        // 记录控件绑定点击处理次数,当次数大于0时,进行点击埋点上报。
        NSArray *actionNames = [self actionsForTarget:target forControlEvent:controlEvents];
        NSLog(@"哈哈哈哈哈这里这里的数量数量%@ %@", actionNames, NSStringFromSelector(action));
        if (actionNames.count == 0 || ![actionNames containsObject:NSStringFromSelector(action)]) {
            NSLog(@"这里的原始数量%ld %@", [self lbtracker_clickActionCounts], self);
            [self setAutotracker_clickActionCounts:[self autotracker_clickActionCounts] + 1];
        }
    }
    
    [self autotracker_addCagegoryTarget:target
                                 action:action
                       forControlEvents:controlEvents];
}

- (void)lbtracker_removeCagegoryTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents
{
    // 减少控件绑定点击处理次数,当次数大于0时,进行点击埋点上报。
    NSArray *actionNames = [self actionsForTarget:target forControlEvent:controlEvents];
    if (actionNames.count > 0 && [actionNames containsObject:NSStringFromSelector(action)]) {
        APLogInfo(@"AutoTrack", @"Click %@ remove T", NSStringFromSelector(action));
        [self setlbTracker_clickActionCounts:[self lbtracker_clickActionCounts] - 1];
    }
    [self lbtracker_removeCagegoryTarget:target action:action forControlEvents:controlEvents];
}

- (void)lbtracker_monitorAction:(UIControl *)sender forEvent:(UIEvent *)event
{
    LBLog(@"lbTrack", @"Click %@ counts = %@", self.senderAction, @([self lbtracker_clickActionCounts]));
    if (self.skipTrack || 0 == [self lbtracker_clickActionCounts]) {
        return;
    }
    
    [self lbtracker_parseClickPoint:event];
  	//执行埋点操作
}

- (NSString *)actionName {
    return objc_getAssociatedObject(self, monitorActionNameKey);
}

- (void)setActionName:(NSString *)monitorActionName{
    objc_setAssociatedObject(self, monitorActionNameKey,
                             monitorActionName,
                             OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSString *)senderAction {
    return objc_getAssociatedObject(self, KSenderAction);
}

- (void)setSenderAction:(NSString *)senderAction{
    objc_setAssociatedObject(self, KSenderAction,
                             senderAction,
                             OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSString *)tabButtonId {
    return objc_getAssociatedObject(self, KTabButtonId);
}

- (void)setTabButtonId:(NSString *)tabButtonId {
    objc_setAssociatedObject(self, KTabButtonId, tabButtonId, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSInteger)autotracker_clickActionCounts
{
    NSNumber *counts = objc_getAssociatedObject(self, LBClickActionCounts);
    return [counts integerValue];
}

- (void)setLBtracker_clickActionCounts:(NSInteger)count
{
    NSLog(@"这里的数量这里的数量%ld", count);
    objc_setAssociatedObject(self, LBClickActionCounts, @(count), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}


- (void)lbtracker_parseClickPoint:(UIEvent *)event
{
    // 获取点击位置坐标
    CGPoint clickPoint;
    UITouch *touch = [event touchesForView:self].anyObject;
    if (touch) {
        clickPoint = [touch locationInView:self];
    }
    
    if ([self respondsToSelector:@selector(lbLogModel_auk)]) {
        LBLogModel *model = [self performSelector:@selector(lbLogModel_auk)];
        model.clickPoint = clickPoint;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/981633.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

在Windows实现将Docker Desktop安装至非系统盘(2025年3月测试有效)

前提条件: 需要提前安装好WSL2。 一、下载 下载链接:Docker Desktop: The #1 Containerization Tool for Developers | Dockerhttps://www.docker.com/products/docker-desktop/二、安装 默认安装会安装到C盘(C:\你的用户名\AppData\Loca…

DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)示例1:基础表格

前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 Deep…

【STM32】玩转IIC之驱动MPU6050及姿态解算

目录 前言 一.MPU6050模块介绍 1.1MPU6050简介 1.2 MPU6050的引脚定义 1.3MPU6050寄存器解析 二.MPU6050驱动开发 2.1 配置寄存器 2.2对MPU6050寄存器进行读写 2.2.1 写入寄存器 2.2.2读取寄存器 2.3 初始化MPU6050 2.3.1 设置工作模式 2.3.2 配置采样率 2.3.3 启…

三维重建(十五)——多尺度(coarse-to-fine)

文章目录 一、多尺度与图像金字塔:从全局结构到局部细节二、特征提取与匹配2.1 从数据采集的角度2.2 从数据增强的角度2.3 从特征提取的方式三、以多尺度的方式使用特征3.1 特征提取与匹配3.1.1 多尺度特征检测3.1.2 金字塔匹配3.2 深度估计与立体匹配3.2.1 多尺度立体匹配3.2…

TMS320F28P550SJ9学习笔记2:Sysconfig 配置与点亮LED

今日学习使用Sysconfig 对引脚进行配置,并点亮开发板上的LED4 与LED5 我的单片机开发板平台是 LAUNCHXL_F28P55x 我是在上文描述的驱动库C2000ware官方例程example的工程基础之上进行添加功能的 该例程路径如下:D:\C2000Ware_5_04_00_00\driverlib\f28p…

[Windows] 批量为视频或者音频生成字幕 video subtitle master 1.5.2

Video Subtitle Master 1.5.2 介绍 Video Subtitle Master 1.5.2 是一款功能强大的客户端工具,能够批量为视频或音频生成字幕,还支持批量将字幕翻译成其他语言。该工具具有跨平台性,无论是 mac 系统还是 windows 系统都能使用。 参考原文&a…

Vue3的核心语法【未完】

Vue3的核心语法 OptionsAPI与CompositionAPI Options API(选项式) 和 Composition API (组合式)是 Vue.js 中用于构建组件的两种不同方式。Options API Options API Options API 是 Vue 2 中的传统模式,并在 Vue 3…

计算机视觉|ViT详解:打破视觉与语言界限

一、ViT 的诞生背景 在计算机视觉领域的发展中,卷积神经网络(CNN)一直占据重要地位。自 2012 年 AlexNet 在 ImageNet 大赛中取得优异成绩后,CNN 在图像分类任务中显示出强大能力。随后,VGG、ResNet 等深度网络架构不…

BUU44 [BJDCTF2020]ZJCTF,不过如此1 [php://filter][正则表达式get输入数据][捕获组反向引用][php中单双引号]

题目: 我仿佛见到了一位故人。。。也难怪,题目就是ZJCTF 按要求提交/?textdata://,I have a dream&filenext.php后: ......不太行,好像得用filephp://filter/convert.base64-encode/resourcenext.php 耶?那 f…

区块链-未来世界的网络形态?

前言 各位读者们,时隔半年作者终于想起了自己的账号密码,今天终于又双叒叕更新啦。今天带给大家的内容仍旧是区块链相关,主要谈谈作者对区块链行业的看法,废话不多说让我们开始发车(扶稳坐好)。 引言 过去的几个月中,比…

Linux总结

1 用户与用户组管理 1.1 用户与用户组 //linux用户和用户组 Linux系统是一个多用户多任务的分时操作系统 使用系统资源的用户需要账号进入系统 账号是用户在系统上的标识,系统根据该标识分配不同的权限和资源 一个账号包含用户和用户组 //用户分类 超级管理员 UID…

掌握 findIndex、push 和 splice:打造微信小程序的灵活图片上传功能✨

文章目录 ✨ 掌握 findIndex、push 和 splice:打造微信小程序的灵活图片上传功能 🌟示例场景:小程序图片上传🌼 认识 findIndex定义语法在代码中的应用示例当前行为 🚀 认识 push定义语法在代码中的应用示例特点 ✂️ …

【Java】—— 堆

一、堆的定义 在计算机科学中,堆(heap)是一种特殊的树状数据结构。用于存储和管理数据。堆通常用于实现优先队列。其中具有最高(或最低)优先级的元素始终位于堆的根部。 堆分为最小堆和最大堆两种类型: …

Windows 使用 Docker + WSL2 部署 Ollama(AMD 显卡推理)搭建手册‌

Windows 使用 Docker WSL2 部署 Ollama(AMD 显卡推理)搭建手册‌ ‌手册目标‌ 在 Windows 11 上通过 ‌Docker WSL2‌ 调用 AMD 显卡运行 Ollama 推理服务。 实现 ‌低延迟、高性能的本地模型推理‌,同时不影响 Windows 正常使用。 标记…

【每天认识一个漏洞】shiro反序列化漏洞

🌝博客主页:菜鸟小羊 💖专栏:Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具 以下是在实际业务中遇到的一个漏洞,仅用来学习,通过暴露的 /actuator/heapdump 端点获取 Shiro key…

【AI大模型】DeepSeek + Kimi 高效制作PPT实战详解

目录 一、前言 二、传统 PPT 制作问题 2.1 传统方式制作 PPT 2.2 AI 大模型辅助制作 PPT 2.3 适用场景对比分析 2.4 最佳实践与推荐 三、DeepSeek Kimi 高效制作PPT操作实践 3.1 Kimi 简介 3.2 DeepSeek Kimi 制作PPT优势 3.2.1 DeepSeek 优势 3.2.2 Kimi 制作PPT优…

音频3A测试--AGC(自动增益)和NS(降噪)测试

一、测试前期准备 一台电脑:用于作为控制播放和录制数据; 一台音频处理器(调音台):控制每个通道播放的数据,如噪声、人工头、模拟设备B输入的数据、收集标准麦克风,设备A处理完成的数据; 四个高保真音响&…

zabbix配置邮件告警

目录 实现步骤: 实现目的: 1.在监控端操作: 2.web界面部署 ​​​​​​​实现步骤: 1、在 zabbix服务端配置邮件发送脚本和修改 zabbix服务端配置文件; 2、在 zabbix前端控制台进行相关设置。 实现目的: Zab…

PHP fastadmin 学习

安装php环境安装mysql插件 修改 php.ini下载 phpstudy、fastadmin 错误 安装FastAdmin could not find driver 参考链接 安装插件 创建1.php <? phpinfo(); ?>运行 http://127.0.0.1/1.php 查看 POD 页面访问404 伪静态 Apache <IfModule mod_rewrite.c> O…

PARETO PROMPT OPTIMIZATION

题目 帕累托提示优化 论文地址&#xff1a;https://openreview.net/forum?idHGCk5aaSvE 摘要 自然语言迅速优化或及时工程已成为一种强大的技术&#xff0c;可以解锁大型语言模型&#xff08;LLMS&#xff09;的各种任务的潜力。尽管现有方法主要集中于最大化LLM输出的单一特…