传送门:
一、埋点分类
目前,业界主流的埋点方式主要有如下三 种。
1、代码埋点
应用程序集成埋点SDK后,在启动时初始化埋点SDK,然后在某个事件发生的时候调用埋点SDK提供的方法来触发事件。
1.1、优点
- 可以精准控制埋点的位置
- 可以方便、灵活地自定义事件和属性
- 可以采集更丰富的和业务相关的数据
- 可以满足更加精细化的分析需求
1.2、缺点
- 前期埋点的成本相对较高
- 若分析需求或事件发生变化,则需要修改应用程序埋点并发版
2、全埋点
全埋点也叫无埋点、无码埋点、无痕埋点、自动埋点,指无须应用程序开发工程师写代码或者只写少量的代码,即可预先自动收集用户的所有或者绝大部分的行为数据,然后根据实际的业务分析需求从中筛选出所需的数据并进行分析。
2.1、全埋点可以采集的事件
-
应用程序的启动事件(
$AppStart
)
· 冷启动:应用程序被系统终止后,在这种状 态下启动的应用程序。
· 热启动:应用程序没有被系统终止,仍在后 台运行,在这种状态下启动的应用程序 -
应用程序退出事件(
$AppEnd
)
·双击Home键切换到其他应用程序。
·单击Home键让当前应用程序进入后台。
·双击Home键并上滑,强杀当前应用程序。
·当前应用程序发生崩溃导致应用程序退出。 -
页面浏览事件(
$AppViewScreen
)
应用程序内的页 面浏览事件,对于iOS应用程序来说,就是指切换 不同的UIViewController
。 -
控件单击事件(
$AppClick
)
控件点击事件,比如 点击UIButton
、UITableView
等。 - 应用程序崩溃事件
2.2、优点
- 前期埋点成本相对低
- 若分析需求或事件设计发生变化,无须应用程序修改埋点并发版
- 可以有效地解决历史数据回朔问题
2.3、 缺点
- 很难做到全面的覆盖
- 无法自动采集和业务相关的数据
- 无法满足更精细化的分析数据
- 各种兼容性能方面问题
3、可视化埋点
可视化埋点也叫圈选,是指通过可视化的方式进行埋点
3.1、可视化埋点一般有两种应用场景
- 默认情况下,不进行任何埋点,然后通过可视化的方式指定给哪些控件进行埋点(指定埋点)
- 默认情况下,全部进行埋点,然后通过可视化的方式指定不给哪些控件进行埋点(排除埋点)。
3.2、优缺点
可视化埋点的优点和缺点,整体上与全埋点的优点和缺点类似。
二、全埋点
正常情况下,iOS应用程序主要有5种常见的状态。
- (1
)Not running
。非运行状态,指应用程序 还没有被启动,或者已被系统终止。 - (2)
Inactive
。前台非活动状态,指应用程序 即将进入前台状态,但当前未接收到任何事件 (可能正在执行其他代码)。应用程序通常只在 转换到其他状态时才会短暂地进入该状态。 - (3)
Active
。前台活跃状态,指应用程序正 在前台运行,可接收事件并进行处理。这也是一 个iOS应用程序处于前台的正常模式。 - (4)
Background
。进入后台状态,指应用程 序进入后台并可执行代码。大多数应用程序在被 挂起前都会短暂地进入该状态。 - (5)
Suspended
。挂起状态,指应用程序进 入后台但没有执行任何代码,系统会自动地将应 用程序转移到该状态,并且在执行该操作前不会 通知应用程序。挂起时,应用程序会保留在内存 中,但不执行任何代码。当系统出现内存不足情 况时,系统可能会在未通知应用程序的情况下清 除被挂起的应用程序,为前台应用程序尽可能腾 出更多的运行资源。
在应用程序的状态转换过程中,系统会回调 实现UIApplicationDelegate
协议类的一些方法(如 在Demo中,Xcode默认创建AppDelegate类),并发送相应的本地通知(系统会先回调相应的方法,待回调方法执行后,再发送相应的通知)。 回调方法和本地通知的对应关系,如下图所示:
这里我创建一个SDK工具类(SensorsSDK
),方便后续集成。
新建一个SensorsSDK
工具SDK,如下图所示:
基本预置属性
一般情况下,用户触发的任何事件都携带一些最基本的信息,比如操 作系统类型、操作系统版本号、运营商信息、应用程序版本号、生产厂商 等,这些信息都可以由埋点SDK自动采集。我们把这些默认由埋点SDK自 动采集的事件基本信息(属性)称为预置属性。 当前你也可以定义需要采集的其他信息。
我们可以在SensorsAnalyticsSDK
类初始化时获取这些预置属性,然后 在触发事件时,将这些预置属性添加到每一个事件中。 首先,在SensorsAnalyticsSDK.m
文件中新增一个 NSDictionary<NSString *,**id**>
类型的属性automaticProperties
,用于保存事件 的预置属性。
说明: $
为区分系统定义的事件标识前缀
预置属性 | 说明 |
---|---|
$os | 操作系统类型 |
$lib | SDK类型 |
$manufacturer | 设置制造商 |
$lib_version | SDK版本号 |
$os_version | 操作系统版本号 |
$model | 手机型号 |
$app_version | 应用程序版本号 |
注意点
- 下拉通知栏时,系统会发送
UIApplicationWillResignActiveNotification
本地通知;上滑 通知栏时,系统会发送UIApplicationDidBecomeActiveNotification
本地通知。 - 上滑控制中心时,系统会发送
UIApplicationWillResignActiveNotification
本地通知;下拉控制中心时,系统会发送UIApplicationDidBecomeActiveNotification
本地通知。 - 双击Home键进入切换应用程序页面时,系统会发送
UIApplicationWillResignActive-Notification
本地通知;选择 当前应用程序,系统会发送UIApplicationDidBecome- ActiveNotification
本地通知。
示例代码如下:
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface SensorsAnalyticsSDK : NSObject
/**
@abstract 获取SDK实例
@return返回单例
*/
+ (SensorsAnalyticsSDK *)sharedInstance;
@end
@interface SensorsAnalyticsSDK (Track)
/**
@abstract 调用Track接口,触发事件
@discussion properties是一个NSDictionary(字典)。 其中,key是属性的名称,必须是NSString类型;value则是属性的内容
@param eventName 事件名称
@param properties 事件属性
*/
- (void)track:(NSString *)eventName properties:(nullable NSDictionary<NSString *, id> *)properties;
@end
#import "SensorsAnalyticsSDK.h"
//获取手机设备型号
#import <sys/sysctl.h>
//SDK系统版本号
static NSString *const SensorsAnalyticsVersion = @"1.0.0";
@interface SensorsAnalyticsSDK ()
/// 由SDK默认自动采集的事件属性即预置属性
@property (nonatomic, strong) NSDictionary<NSString *, id> *automaticProperties;
/// 标记应用程序是否已收到UIApplicationWillResignActiveNotification本地通知
@property (nonatomic, assign) BOOL applicationWillResignActive;
///是否为被动启动(后台应用程序刷新)
@property (nonatomic, getter=isLaunchedPassively) BOOL launchedPassively;
@end
@implementation SensorsAnalyticsSDK
- (void)dealloc
{
[[NSNotificationCenter defaultCenter]removeObserver:self];
}
+ (SensorsAnalyticsSDK *)sharedInstance {
static SensorsAnalyticsSDK *sdk = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sdk = [[SensorsAnalyticsSDK alloc] init];
});
return sdk;
}
- (instancetype)init {
self = [super init];
if (self) {
_automaticProperties = [self collectAutomaticProperties];
//设置是否位被动启动标记
_launchedPassively = UIApplication.sharedApplication.backgroundTimeRemaining != UIApplicationBackgroundFetchIntervalNever;
//添加应用程序监听
[self setupListeners];
}
return self;
}
#pragma mark- Properties
-(NSDictionary<NSString *,id> *)collectAutomaticProperties {
NSMutableDictionary *properties = [NSMutableDictionary dictionary];
//操作系统
properties[@"$os"] = @"iOS";
//SDK类型
properties[@"$lib"] = @"iOS";
//设置制造商
properties[@"$manufacturer"] = @"Apple";
//SDK版本号
properties[@"$lib_version"] = SensorsAnalyticsVersion;
//操作系统版本号
properties[@"$os_version"] = UIDevice.currentDevice.systemVersion;
//手机型号
properties[@"$model"] = [self deviceModel];
//应用程序版本号
properties[@"$app_version"] = NSBundle.mainBundle.infoDictionary[@"CFBundleShortVersionString"];
return [properties copy];
}
//获取手机的型号
-(NSString *) deviceModel {
size_t size;
sysctlbyname("hw.machine", NULL, &size, NULL, 0);
char answer[size];
sysctlbyname("hw.machine", answer, &size, NULL, 0);
NSString *results = @(answer);
return results;
}
-(void)printEvent:(NSDictionary *)event {
#if DEBUG
NSError *error = nil;
NSData *data = [NSJSONSerialization dataWithJSONObject:event options:NSJSONWritingSortedKeys error:&error];
if (error) {
return NSLog(@"Json Serialzed error:%@",error);
}
NSString *json = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"[event]:%@",json);
#endif
}
#pragma mark - 监听
-(void)setupListeners {
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
//监听App进入后台
[center addObserver:self selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
//监听App进入前台并处于活跃状态
[center addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
//监听UIApplicationWillResignActiveNotification本地通知
[center addObserver:self selector:@selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
//注册监听UIApplicationDidFinishLaunchingNotification本地通知
[center addObserver:self selector:@selector(applicationDidFinishLaunching:) name:UIApplicationDidFinishLaunchingNotification object:nil];
}
-(void)applicationDidEnterBackground:(NSNotification *)notification {
NSLog(@"App进入后台");
//还原标记位
self.applicationWillResignActive = NO;
//触发$AppEnd事件
[self track:@"$AppEnd" properties:nil];
}
-(void)applicationDidBecomeActive:(NSNotification *)notification {
NSLog(@"App进入前台");
//还原标记位
if (self.applicationWillResignActive) {
self.applicationWillResignActive = NO;
return;
}
//将启动标记设为NO.正常记录事件
self.launchedPassively = NO;
//触发$AppStart事件
[self track:@"$AppStart" properties:nil];
}
-(void)applicationWillResignActive:(NSNotification *)notification {
NSLog(@"App即将进入前台");
self.applicationWillResignActive = YES;
}
-(void)applicationDidFinishLaunching:(NSNotification *)notification {
NSLog(@"App启动啦");
//当应用程序后台运行时,触发被动启动事件
if (self.isLaunchedPassively) {
[self track:@"$AppStartPassively" properties:nil];
}
}
@end
@implementation SensorsAnalyticsSDK (Track)
- (void)track:(NSString *)eventName properties:(NSDictionary<NSString *,id> *)properties {
NSMutableDictionary *event = [NSMutableDictionary dictionary];
// 设置事件名称
event[@"event"] = eventName;
// 设置事件发生的时间戳,单位为毫秒
event[@"time"] = [NSNumber numberWithLong:NSDate.date.timeIntervalSince1970 * 1000];
NSMutableDictionary *eventProperties = [NSMutableDictionary dictionary];
// 添加预置属性
[eventProperties addEntriesFromDictionary:self.automaticProperties];
// 添加自定义属性
[eventProperties addEntriesFromDictionary:properties];
//判断是否位被动启动状态
if(self.isLaunchedPassively) {
//添加应用程序状态属性
eventProperties[@"$app_state"] = @"background";
}
// 设置事件属性
event[@"properties"] = eventProperties;
[self printEvent:event];
}
@end
网友评论