热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

iOS无埋点数据采集

移动开发经过前几年爆炸式的增长之后,移动开发进入了一个精细化管理操作的时期,除了拓展自己的能力,在移动开发外寻求到更好的职业道路这条路外,移动开发这份工
移动开发经过前几年爆炸式的增长之后,移动开发进入了一个精细化管理操作的时期,除了拓展自己的能力,在移动开发外寻求到更好的职业道路这条路外,移动开发这份工作的做法怕也是需要有一番观念上的变动。

为什么做数据采集

对于应用内的定向、精细化管理,其中重要一点就是App内数据采集。

  1. 用户使用最多的功能是什么?
  2. 用户停留时间最长的页面是哪个?
  3. 用户增长量、使用时段是怎么样分布?
    等等问题,需要从线上App中采集到最真实的数据,经过合理分析,对未来产品进行直观数据性的指导,着重设计出更符合用户使用习惯的产品功能。

数据采集怎么做

埋点数据采集

数据采集可分为 埋点数据采集和无埋点数据采集,从名字字面可以分出二者的区别,埋点数据采集目前国内的主要第三方数据分析服务商,如百度统计、友盟、TalkingData 等都提供了这一方案,以友盟提供SDK为例


//自动页面时长统计, 开始记录某个页面展示时长.
+ (void)beginLogPageView:(NSString *)pageName;
//自动页面时长统计, 结束记录某个页面展示时长.
+ (void)endLogPageView:(NSString *)pageName;
//结构化事件
+ (void)event:(NSArray *)keyPath value:(int)value label:(NSString *)label;

在需要进行统计的页面上进行数据采集埋点,调用SDK对应提供的API,完成数据统计,埋点数据采集的好处是在于:调用直观简单、API对开发者友好、另外由于这些大厂商进入该领域很早,已经占领了很大的移动开发市场有了很健壮便捷的服务提供、同时提供了非常丰富的各种表项。

不好的地方在于:

  1. 数据采集买点代码与项目代码混合在一起,增加了项目开发、维护的成本,每一处埋点都需要合理、明晰的说明才能保证项目在迭代中不会因为改动失去部分数据的采集;
  2. 埋点代码是在开发中预先写入的,需要跟随相应版本进行调整;
  3. 埋点代码上线后与业务代码是同等级别,当出现错埋、漏埋等情况,无法动态更新及添加;

无埋点数据采集

在介绍无埋点数据采集之前,首先需要将Objective-C 作为动态语言的特性进行讲解,这是实现无埋点数据采集的基石。

Objective-C作为动态语言,Class在是runtime中创建的, selector, method, imp, protocol等都是随后绑定上去的,这是所谓的运行时绑定。一个典型的例子如下
这里写图片描述

首先在runtime中能够查出当前运行时环境中所有的类,每个类中的方法,每个类消息的绑定,每个类的实现的协议,每个协议的定义,每个类当前的消息缓存等一切你想知道的东西。

其次runtime底层Class实现是对消息转发实现的,Class的方法调用都是间接的。

基于以上两个特性促成了Objective-C的黑魔法 Method Swizzling,Method Swizzling的实现逻辑如下图所示。

这里写图片描述

新建一个数据节点采集的类,交换被采集的类和 采集节点的 对应两个selector对应的IMP。在采集节点中对数据进行收集。

在以上基础上,对Objective-C中的类接口进行对应数据的采集。

系统类数据采集

iOS提供的基础类的selecter都是已知的,因此较为简单,只需要通过在对应类调用之前进行对应接口的hook,在hook方法中进行相应的数据采集即可。

下面的例子以对UIViewController 为例,在每个页面中采集用户在一个页面内停留的时间,实现代码如下:

这里写图片描述

在声明的对进行数据采集分析的类 CCAnalyseViewControllerAnalyseNodeload 方法中加入对UIViewController 两个方法和本类的方法的IMP进行交换。

这里写图片描述

- (void)viewDidAppear:(BOOL)animated;

- (void)viewDidDisappear:(BOOL)animated;

CCAnalyseViewControllerAnalyseNode 实例化之后,每个UIViewController 在加载、退出的时候调用上面两个方法时,执行顺序如下图所示:

这里写图片描述

此时就能够在UIViewController 对应2个方法中都加入了可以用来相应数据采集的方法,就可以在对应的hook方法中进行页面停留时间的采集。
思路同上,如果需要对用户操作习惯和常用功能的进行统计,可以对UIControl 方法进行hook实现。
这里写图片描述

这里写图片描述

除此之外,对于 UITableViewUIViewController 常用的控件,可以通过hook 对应的 delegate 方法,获取在实际使用中业务赋值给对应cell的数据、或者cell点击事件。

以上两个例子是对系统提供的类进行数据采集的例子。

用户自定义类数据采集

正如上一节开头所言,由于系统提供类selector都是已知的,所以实现起来较为简单,而对于用户自定义类在selector未知的情况下,如何进行hook?
首先在采集节点中植入一个能够对所有 Class 进行解析的 接口,然后通过线上进行部署,其次将Class的ClassName、seletor参数下发给数据采集SDK,实现对用户自定义Class的数据采集。

  1. 用户自定义Class未知selector在采集节点中IMP的插入
- (void) analyseUserdefinedTarget:(NSString *)targetClass action:(nullable SEL)action method:(IMP)method;

该接口的具体实现为:

- (void) analyseUserdefinedTarget:(NSString *)targetClass action:(nullable SEL)action method:(IMP)method{

if (targetClass !=nil && action !=nil) {
Class target = NSClassFromString(targetClass);
NSObject *temp = [[target alloc]init];
if ([temp respondsToSelector:action]) {
NSString * methodName = NSStringFromSelector(action);
Method m_gesture = class_getInstanceMethod([target class], action);

SEL hook_sel = NSSelectorFromString([NSString stringWithFormat:@"hook_%@",methodName]);
if (method == nil) {
method = (IMP) myHookMethodIMP;
}

if (![[CCAnalyseBasicAnalyseNode sharedInstance] respondsToSelector:hook_sel]) {
class_addMethod([CCAnalyseBasicAnalyseNode class], hook_sel, method, method_getTypeEncoding(m_gesture));
class_addMethod([target class], hook_sel, method_getImplementation(m_gesture), method_getTypeEncoding(m_gesture));
}

method_setImplementation(m_gesture, class_getMethodImplementation([CCAnalyseBasicAnalyseNode class], hook_sel));


}

}
}

以上代码的逻辑是:对用户自定义Class进行selector检查,如果该类的确有对应接口,才需要对爱selector进行hook,避免对未声明的selector进行处理出现崩溃。在采集节点中去检查添加的hook接口是否存在,不存的话,在runtime中添加selector、和对应的IMP;最后将被采集用户自定义类的selector指向的IMP与新添加的IMP进行交换。在myHookMethodIMP中完成对该接口的数据采集分析。
2. IMP的实现、以及IMP中数据采集,以上文中 myHookMethodIMP为例,看IMP的具体实现

void myHookMethodIMP(id self, SEL _cmd,id arg0)
{
if ([self respondsToSelector:_cmd]) {
NSString * methodName = NSStringFromSelector(_cmd);
SEL hook_sel = NSSelectorFromString([NSString stringWithFormat:@"hook_%@",methodName]);

cOntrolInfo= [NSMutableDictionary new];
[controlInfo setObject:[NSString stringWithUTF8String:object_getClassName(self)] forKey:ACTIONTARGET];

[controlInfo setObject:methodName forKey:ACTIONNAME];
[controlInfo setObject:[NSNumber numberWithInteger:ActionTypeUserdefined] forKey:ACTIONTYPE];

if (arg0 !=nil) {
if ([arg0 isKindOfClass:[NSObject class]] ) {

if ([arg0 isKindOfClass:[NSString class]]||[arg0 isKindOfClass:[NSNumber class]]||[arg0 isKindOfClass:[NSArray class]]||[arg0 isKindOfClass:[NSDictionary class]]||[arg0 isKindOfClass:[NSNull class]]) {
[controlInfo setObject:arg0 forKey:ACTIONINFO];
}

}else{

[controlInfo setObject:[NSValue valueWithNonretainedObject:arg0] forKey:ACTIONINFO];
}
}

NSDictionary *reportInfo = @{[NSNumber numberWithInteger:[self hash]]:controlInfo};
addActionReport(reportInfo);

if ([self respondsToSelector:hook_sel]) {
IMP imp = [self methodForSelector:hook_sel];
void (*func)(id, SEL,id) = (void *)imp;
if (imp!=NULL) {
func(self, hook_sel,arg0);
}
}

}
}

在IMP中,采集到该selector接口的参数之外,仍然需要调用原类中IMP,实现原来Class的方法。
iOS 如何实现可变参数的IMP,实现对用户自定义类hook
3. 线上下发需要被采集Class的相关参数;

举如下例子,采集UILabel的 text,使用该节点采集接口使用方式如下

        [[CCAnalyseManager sharedInstance] analyseUserdefinedTarget:@"UILabel" action:@selector(setText:)];

实际使用中,通过线上管理系统向数据采集SDK,下发指令数据,SDK内完成对JSON的解析,即可以实现线上实时管理需要采集的数据。

{
"className": "UILabel",
"selectorName": "setText"
}

综上所述,使用无埋点数据采集方案可以实现埋点数据采集方案不足的地方:
1.实现自动收集基本的页面和事件信息,分离数据采集与业务代码;
2.数据采集类型与需求根据线上配置设置与操控,无需再耗费大量的时间和精力对需要统计的页面和事件挨个单独埋点。
3.线上管理配置、增加数据采集需求时,也无需再次发版。不再为少埋点、漏埋点而发愁。


推荐阅读
  • UI框架哈哈哈
    在前端项目开发过程中,总是会引入一些UI框架,已为方便自己的使用,很多大公司都有自己的一套UI框架,下面就是最近经常使用并且 ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • 基因组浏览器中的Wig格式解析
    本文详细介绍了Wiggle(Wig)格式及其在基因组浏览器中的应用,涵盖variableStep和fixedStep两种主要格式的特点、适用场景及具体使用方法。同时,还提供了关于数据值和自定义参数的补充信息。 ... [详细]
  • 本文详细介绍了中央电视台电影频道的节目预告,并通过专业工具分析了其加载方式,确保用户能够获取最准确的电视节目信息。 ... [详细]
  • TCP长连接设备管理平台:架构与功能概览
    本文介绍了基于TCP长连接的设备管理平台的设计理念、技术选型及主要功能模块。最初,项目旨在实现简单的协议测试,但随着需求扩展,逐步演变为一个完整的前后端分离系统。 ... [详细]
  • 开源组件是什么意思_iView 发布微信小程序 UI 组件库 iView Weapp
    末尾有彩蛋。过去的两年里,iView开源项目已经帮助成千上万的开发者快速完成网站开发,大幅度提高了开发效率,成为Vue.js生态里重要的一 ... [详细]
  • vue.js的ui框架是什么
    小编给大家分享一下vue.js的ui框架是什么,希望大家阅读完这篇文章后大所收获,下面让我们一起去探讨吧!vue.js的ui框架有:Element、iview、vuetify、vu ... [详细]
  • iView 一周年了,同时宣布了 2.0 正式版,但这只是最先...
    两年前,我最先打仗Vue.js框架,当时就被它的轻量、组件化和友爱的API所吸收。以后我将Vue.js和Webpack手艺栈引入我的公司(TalkingData)可视化团队,并经由 ... [详细]
  • 10 个 GitHub 上超火和超好看的管理后台模版,后期工作可能用的上
    大家好,我是你们的超级猫,一个不喜欢吃鱼、又不喜欢喵的超级猫~前言一般人没事的时候刷刷朋友圈、微博、电视剧、知乎,而有些人是没事的时候刷刷 ... [详细]
  • QCon北京2018圆满结束,探索前沿技术最佳实践
    \看新闻很累?看技术新闻更累?试试下载InfoQ手机客户端,每天上下班路上听新闻,有趣还有料!\\\由极客邦科 ... [详细]
  • 深入解析Android自定义View面试题
    本文探讨了Android Launcher开发中自定义View的重要性,并通过一道经典的面试题,帮助开发者更好地理解自定义View的实现细节。文章不仅涵盖了基础知识,还提供了实际操作建议。 ... [详细]
author-avatar
yoyokk99的秋天
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有