iOS 无痕埋点方案及实战分享

简介: iOS 无痕埋点方案及实战分享

前言


所谓埋点就是在应用中特定的流程收集一些信息,用来跟踪应用使用的状况,随着现在的互联网的越来越便利,然后精准分析用户数据变成为一种新的大趋势,用户在这个页面停留时间、点击按钮、浏览内容、手机型号、网络环境等等等都可以进行统计

1.png

要做数据分析不外乎就两种,一种服务器通过接口调用情况统计,另外一种就是前端埋点统计,当然前端埋点统计可以更精准的统计更多数据信息~


埋点方案


大致分为三种,代码埋点、可视化埋点,无埋点


第一种:代码埋点


很简单明了就是在需要统计埋点的控制器和按钮事件等地方做好埋点处理


第二种:可视化埋点


根据标识来识别每一个事件, 针对指定的事件进行取参埋点。而事件的标识与参数信息都写在配置表中,通过动态下发配置表来实现埋点统计


第三种:无埋点


无埋点是指开发人员集成采集 SDK 后,SDK 便直接开始捕捉和监测用户在应用里的所有行为,并全部上报,不需要开发人员添加额外代码

1.png

想关于这三种的介绍,网上资料一大堆,感兴趣的朋友可以自己去搜索看看,

美团点评前端无痕埋点实践


实战处理


统计用户浏览页面


下面是一个很简单的统计用户浏览埋点方式,其实就是利用Runtime交换viewDidLoad方法

+ (void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        kMethodSwizzling(self.class, @selector(viewDidLoad), @selector(kj_viewDidLoad));
    });
}
- (void)kj_viewDidLoad{
    [self kj_viewDidLoad];
    NSString *clazz = NSStringFromClass([self class]);
    NSDictionary *dict = @{
        @"userid":KJHookInfo.shared.userid,
        @"viewController":clazz
    };
    NSString *parameter = dict.jsonString.kj_aesEncryptKey(@"key");
    //TODO:上传数据
}


统计指定页面


升级一下,浏览指定控制器埋点,通过接口动态返回需要统计的界面控制器,储存在hookViewControllers,然后统计

- (void)kj_viewDidLoad{
    [self kj_viewDidLoad];
    NSString *clazz = NSStringFromClass([self class]);
    BOOL isHook = ({
        BOOL isHook = NO;
        for (NSString *name in KJHookInfo.shared.hookViewControllers) {
            if ([name isEqualToString:clazz]) {
                isHook = YES;
                break;
            }
        }
        isHook;
    });
    if (isHook) {
        NSDictionary *dict = @{
            @"userid":KJHookInfo.shared.userid,
            @"viewController":clazz
        };
        NSString *parameter = dict.jsonString.kj_aesEncryptKey(@"key");
        //TODO:上传数据
    }
}


统计用户页面浏览时长


再介绍一个统计页面停留时长的埋点处理 简单讲就是交换viewWillAppear:viewDidDisappear:

+ (void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        kMethodSwizzling(self.class, @selector(viewWillAppear:), @selector(kj_viewWillAppear:));
        kMethodSwizzling(self.class, @selector(viewDidDisappear:), @selector(kj_viewDidDisappear:));
    });
}
- (void)kj_viewWillAppear:(BOOL)animated{
    [self kj_viewWillAppear: animated];
    // 记录进入时间
    KJHookInfo.shared.time = CFAbsoluteTimeGetCurrent();
}
- (void)kj_viewDidDisappear:(BOOL)animated{
    [self kj_viewDidDisappear: animated];
    NSString *clazz = NSStringFromClass([self class]);
    BOOL isHook = ({
        BOOL isHook = NO;
        for (NSString *name in KJHookInfo.shared.hookViewControllers) {
            if ([name isEqualToString:clazz]) {
                isHook = YES;
                break;
            }
        }
        isHook;
    });
    if (isHook) {
        NSTimeInterval time = CFAbsoluteTimeGetCurrent() - KJHookInfo.shared.time;
        NSDictionary *dict = @{
            @"userid":KJHookInfo.shared.userid,
            @"time":time,
            @"viewController":clazz
        };
        NSString *parameter = dict.jsonString.kj_aesEncryptKey(@"key");
        //TODO:上传数据
    }
}


用户点击事件


大多数可点击UI控件都是基于UIControl,核心还是交互方法sendAction:to:forEvent:,下面提供一种统计到某个具体页面的按钮

@implementation UIControl (KJHook)
+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{    
        kMethodSwizzling(self.class, @selector(sendAction:to:forEvent:), @selector(kj_sendAction:to:forEvent:));
    });
}
- (void)kj_sendAction:(SEL)action to:(nullable id)target forEvent:(nullable UIEvent *)event {
    [self kj_sendAction:action to:target forEvent:event];
    _weakself;
    kGCD_async(^{
        if ([NSStringFromClass(weakself.class) isEqualToString:@"UIButton"]) {
            void (^kDealButton)(NSString *) = ^(NSString *clazz){
                NSDictionary *dict = @{
                            @"userid":@"userid",
                            @"centerX":[NSString stringWithFormat:@"%.2f",weakself.centerX],
                            @"centerY":[NSString stringWithFormat:@"%.2f",weakself.centerY],
                            @"viewController":clazz
                        };
                NSString *parameter = dict.jsonString.kj_aesEncryptKey(@"key");
                NSLog(@"%@",parameter);
                //TODO:上传数据
            };
            kGCD_main(^{
                kDealButton(NSStringFromClass([[target viewController] class]));
            });
        }
    });
}
@end


这里如果想更准确,还可给每个按钮编tag值,当然这个工程量就比较大,这边只是提供思路,具体怎么做示实际情况为准


这里值得一提的就是,在交换方法的时候,一定要全局查询是否命名冲突(有没有方法名重复),否则可能会出现你埋点的方法压根不执行,原理可以参考我另外一篇关于Category介绍的文章iOS Category类别的使用及工具封装


埋点后续处理


接口数据上传


通常我们埋好点之后,采取的方式都是调用服务器的一个指定接口,但是有一个缺陷就是在高峰期时刻访问量会非常巨大,就有超出服务器范围的可能


图片访问式统计


先来介绍网址链接的构成,https://upload-images.jianshu.io/upload_images/1933747-82138031f05852ab.gif?tR8XBkv3BaBjjEeck9VbeiZauP73MdXWlhvmUq+BAFY=

scheme:https  
host:upload-images.jianshu.io
path:/upload_images/1933747-82138031f05852ab.gif
query:tR8XBkv3BaBjjEeck9VbeiZauP73MdXWlhvmUq+BAFY=

正常我们访问一张图片,其实只需要scheme:// + host + path 三部分就可以正常访问

但是下面这张格式组成 scheme:// + host + path + ? + query 也是可以正常访问

所以我们可以将埋点信息放在query当中,然后只需要统计这张图片的访问记录就可以简单快捷的拿到埋点的内容

带宽考虑:图片我们也可以采用1像素的图片,这样也不会怎么占用服务器的带宽

安全考虑:同样我们也可以将需要的参数加密

NSDictionary *dict = @{@"app":@"appname"};
NSString *parameter = dict.jsonString.kj_aesEncryptKey(@"key");

同样也是可以访问到图片地址https://upload-images.jianshu.io/upload_images/1933747-82138031f05852ab.gif?tR8XBkv3BaBjjEeck9VbeiZauP73MdXWlhvmUq+BAFY=


后续思考


我们都知道访问得到的图片都是data数据,那么我们是否也可以把我们想要反馈给客户端的数据藏于data当中解析呢?


那么大家还有什么比较优秀的埋点方式呢?欢迎分享,谢谢~


备注:本文用到的部分函数方法和Demo,均来自三方库**KJCategories**,如有需要的朋友可自行pod 'KJEmitterView'引入即可


无痕埋点方案及实战分享介绍就到此完毕,后面有相关再补充,写文章不容易,还请点个**小星星**传送门

相关文章
|
8月前
|
存储 数据建模 数据库
IOS开发数据存储:什么是 UserDefaults?有哪些替代方案?
IOS开发数据存储:什么是 UserDefaults?有哪些替代方案?
121 0
|
移动开发 安全 数据安全/隐私保护
ios安全加固 ios 加固方案
4.1字符串加密字符串会暴露APP的很多关键信息,攻击者可以根据界面显示的字符串,快速找到相关逻辑的处理函数,从而进行分析破解。加密字符串可以增加攻击者阅读代码的难度以及根据字符串静态搜索的难度。
|
2月前
|
监控 算法 iOS开发
深入探索iOS函数调用栈:符号化与性能调优实战
在iOS开发中,理解函数调用栈对于性能调优和问题排查至关重要。函数调用栈记录了程序执行过程中的函数调用顺序,通过分析调用栈,我们可以识别性能瓶颈和潜在的代码问题。本文将分享iOS函数调用栈的基本概念、符号化过程以及如何利用调用栈进行性能调优。
42 2
|
5月前
|
测试技术 Linux 虚拟化
iOS自动化测试方案(五):保姆级VMware虚拟机安装MacOS
详细的VMware虚拟机安装macOS Big Sur的保姆级教程,包括下载VMware和macOS镜像、图解安装步骤和遇到问题时的解决方案,旨在帮助读者顺利搭建macOS虚拟机环境。
204 3
iOS自动化测试方案(五):保姆级VMware虚拟机安装MacOS
|
5月前
|
测试技术 开发工具 iOS开发
iOS自动化测试方案(三):WDA+iOS自动化测试解决方案
这篇文章是iOS自动化测试方案的第三部分,介绍了在没有MacOS系统条件下,如何使用WDA(WebDriverAgent)结合Python客户端库facebook-wda和tidevice工具,在Windows系统上实现iOS应用的自动化测试,包括环境准备、问题解决和扩展应用的详细步骤。
412 1
iOS自动化测试方案(三):WDA+iOS自动化测试解决方案
|
5月前
|
测试技术 数据安全/隐私保护 iOS开发
iOS自动化测试方案(四):保姆级搭建iOS自动化开发环境
iOS自动化测试方案的第四部分,涵盖了基础环境准备、iPhone虚拟机设置、MacOS虚拟机与iPhone真机的连接,以及扩展问题和代码示例,确保读者能够顺利完成环境搭建并进行iOS自动化测试。
484 0
iOS自动化测试方案(四):保姆级搭建iOS自动化开发环境
|
5月前
|
测试技术 虚拟化 iOS开发
iOS自动化测试方案(二):Xcode开发者工具构建WDA应用到iphone
这篇文章是iOS自动化测试方案的第二部分,详细介绍了在Xcode开发者工具中构建WebDriverAgent(WDA)应用到iPhone的全过程,包括环境准备、解决构建过程中可能遇到的错误,以及最终成功安装WDA到设备的方法。
248 0
iOS自动化测试方案(二):Xcode开发者工具构建WDA应用到iphone
|
5月前
|
测试技术 开发工具 虚拟化
iOS自动化测试方案(一):MacOS虚拟机保姆级安装Xcode教程
这篇文章提供了一份保姆级的教程,指导如何在MacOS虚拟机上安装Xcode,包括环境准备、基础软件安装以及USB扩展插件的使用,以实现iOS自动化测试方案的第一步。
246 0
iOS自动化测试方案(一):MacOS虚拟机保姆级安装Xcode教程
|
5月前
|
JSON 搜索推荐 定位技术
打造个性化天气应用:iOS开发实战
【8月更文挑战第31天】在这篇文章中,我们将一起探索如何从零开始构建一个iOS天气应用。通过简单易懂的步骤,你将学习到如何使用Swift编程语言和苹果的开发工具Xcode来实现这个目标。我们会涉及到用户界面设计、网络编程以及数据解析等关键技能,确保你能够顺利地完成这个项目。无论你是初学者还是有一定经验的开发者,这篇文章都会带给你新的启发和收获。
|
8月前
|
移动开发 安全 数据安全/隐私保护
ios安全加固 ios 加固方案
ios安全加固 ios 加固方案
105 1
ios安全加固 ios 加固方案