热门标签 | 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.线上管理配置、增加数据采集需求时,也无需再次发版。不再为少埋点、漏埋点而发愁。


推荐阅读
  • iView 一周年了,同时宣布了 2.0 正式版,但这只是最先...
    两年前,我最先打仗Vue.js框架,当时就被它的轻量、组件化和友爱的API所吸收。以后我将Vue.js和Webpack手艺栈引入我的公司(TalkingData)可视化团队,并经由 ... [详细]
  • 10 个 GitHub 上超火和超好看的管理后台模版,后期工作可能用的上
    大家好,我是你们的超级猫,一个不喜欢吃鱼、又不喜欢喵的超级猫~前言一般人没事的时候刷刷朋友圈、微博、电视剧、知乎,而有些人是没事的时候刷刷 ... [详细]
  • UI框架哈哈哈
    在前端项目开发过程中,总是会引入一些UI框架,已为方便自己的使用,很多大公司都有自己的一套UI框架,下面就是最近经常使用并且 ... [详细]
  • AARRR:数据运营模型
    一、基础知识产品经理《增长黑客》数据分析基础--获取(Acquisition)--激活(Activation)--留存(Retention)--收入(Revenue)--传播(Re ... [详细]
  • 本文介绍如何通过Windows批处理脚本定期检查并重启Java应用程序,确保其持续稳定运行。脚本每30分钟检查一次,并在需要时重启Java程序。同时,它会将任务结果发送到Redis。 ... [详细]
  • 本章将深入探讨移动 UI 设计的核心原则,帮助开发者构建简洁、高效且用户友好的界面。通过学习设计规则和用户体验优化技巧,您将能够创建出既美观又实用的移动应用。 ... [详细]
  • 堆是一种常见的数据结构,广泛应用于计算机科学领域。它通常表示为一棵完全二叉树,并可通过数组实现。堆的主要特性是每个节点的值与其父节点的值之间存在特定的关系,这使得堆在优先队列和排序算法中非常有用。 ... [详细]
  • 为了解决不同服务器间共享图片的需求,我们最初考虑建立一个FTP图片服务器。然而,考虑到项目是一个简单的CMS系统,为了简化流程,团队决定探索七牛云存储的解决方案。本文将详细介绍使用七牛云存储的过程和心得。 ... [详细]
  • 主调|大侠_重温C++ ... [详细]
  • 本文探讨了在iOS平台上开发BLE(蓝牙低功耗)应用程序时遇到的挑战,特别是如何实现应用在后台模式下仍能持续扫描并连接蓝牙设备。文章提供了具体的配置方法和常见的问题解决方案。 ... [详细]
  • 本文针对初学者在创建Android项目时遇到的R.java文件错误提供了解决方案,通过实际案例和详细的日志分析,帮助读者快速定位并解决问题。 ... [详细]
  • 本文详细介绍了如何正确安装Java EE SDK,并解决在安装过程中可能遇到的问题,特别是关于servlet代码在Apache Tomcat 10中无法运行的情况。 ... [详细]
  • 微信小程序中实现位置获取的全面指南
    本文详细介绍了如何在微信小程序中实现地理位置的获取,包括通过微信官方API和腾讯地图API两种方式。文中不仅涵盖了必要的准备工作,如申请开发者密钥、下载并配置SDK等,还提供了处理用户授权及位置信息获取的具体代码示例。 ... [详细]
  • 智慧城市建设现状及未来趋势
    随着新基建政策的推进及‘十四五’规划的实施,我国正步入以5G、人工智能等先进技术引领的智慧经济新时代。规划强调加速数字化转型,促进数字政府建设,新基建政策亦倡导城市基础设施的全面数字化。本文探讨了智慧城市的发展背景、全球及国内进展、市场规模、架构设计,以及百度、阿里、腾讯、华为等领军企业在该领域的布局策略。 ... [详细]
  • 不仅数据分析师的招聘中要求具备可视化,和使用PPT制作分析报告的技能。对于非数据分析师的岗位,例如产品、市场、运营等,每天也会接触大量的图 ... [详细]
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社区 版权所有