项目中需要统计的数据包括
1.在某个页面的停留时间(针对UIViewController)
2.某个事件(method)触发的次数
3.某个View的展示次数
(目前属于试验阶段)
1.停留时间runtime swap viewDidAppear & viewDidDisAppear
#import "UIViewController+JHswizzling.h"
static NSDate *startDate;
@implementation UIViewController (JHswizzling)
+ (void)load{
// 通过class_getInstanceMethod()函数从当前对象中的method list获取method结构体,如果是类方法就使用class_getClassMethod()函数获取。
Method fromMethod = class_getInstanceMethod([self class], @selector(viewDidAppear:));
Method toMethod = class_getInstanceMethod([self class], @selector(JH_swizzlingViewDidAppear));
/**
* 我们在这里使用class_addMethod()函数对Method Swizzling做了一层验证,如果self没有实现被交换的方法,会导致失败。
* 而且self没有交换的方法实现,但是父类有这个方法,这样就会调用父类的方法,结果就不是我们想要的结果了。
* 所以我们在这里通过class_addMethod()的验证,如果self实现了这个方法,class_addMethod()函数将会返回NO,我们就可以对其进行交换了。
*/
if (!class_addMethod([self class], @selector(JH_swizzlingViewDidAppear), method_getImplementation(toMethod), method_getTypeEncoding(toMethod))) {
method_exchangeImplementations(fromMethod, toMethod);
}
// 通过class_getInstanceMethod()函数从当前对象中的method list获取method结构体,如果是类方法就使用class_getClassMethod()函数获取。
Method fromMethodDis = class_getInstanceMethod([self class], @selector(viewDidDisappear:));
Method toMethodDis = class_getInstanceMethod([self class], @selector(JH_swizzlingViewDidDisAppear));
if (!class_addMethod([self class], @selector(JH_swizzlingViewDidDisAppear), method_getImplementation(toMethodDis), method_getTypeEncoding(toMethodDis))) {
method_exchangeImplementations(fromMethodDis, toMethodDis);
}
}
// 我们自己实现的方法,也就是和self的viewDidAppear方法进行交换的方法。
- (void)JH_swizzlingViewDidAppear{
NSString *str = [NSString stringWithFormat:@"%@", self.class];
// 我们在这里加一个判断,将系统的UIViewController的对象剔除掉
NSDictionary *data = [self getJsonData];
if ([[data allKeys]containsObject:str]) {
if(![str containsString:@"UI"]){
startDate = [NSDate date];
NSLog(@"统计打点出现 : %@ time : %@", [self getJsonData][str] ,startDate);
}
}
[self JH_swizzlingViewDidAppear];
}
// 我们自己实现的方法,也就是和self的viewDidDisAppear方法进行交换的方法。
- (void)JH_swizzlingViewDidDisAppear{
NSString *str = [NSString stringWithFormat:@"%@", self.class];
// 我们在这里加一个判断,将系统的UIViewController的对象剔除掉
NSDictionary *data = [self getJsonData];
if ([[data allKeys]containsObject:str]) {
if(![str containsString:@"UI"]){
//计算时间差
NSDate *endDate = [NSDate date];
NSTimeInterval duration = [endDate timeIntervalSinceDate:startDate];
NSLog(@"统计打点出现 : %@ time : %f 时长", data[str] ,duration);
//组合数据并存入数据库
NSDictionary *vcDic = @{@"viewControllerCodeName":str,
@"viewControllerName":data[str],
@"viewControllerTime":[NSString stringWithFormat:@"%f",duration],
};
[JH_AnalyseDataHelper _AnalyseWithData:vcDic withType:AnalyseTypeViewController];
}
}
[self JH_swizzlingViewDidDisAppear];
}
-(NSDictionary *)getJsonData{
NSString *filePath = [[NSBundle mainBundle]pathForResource:@"analyse" ofType:@"json"];
NSData *jsonData = [NSData dataWithContentsOfFile:filePath];
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableLeaves error:nil];
return dic[@"viewController"];
}
2.某个事件(method)触发的次数,针对系统控件
#import "JHAnalyseControlAnalyseNode.h"
@implementation JHAnalyseControlAnalyseNode
+(void)load{
Method JH_sendAction = class_getInstanceMethod([UIControl class], @selector(sendAction:to:forEvent:));
class_addMethod([UIControl class], @selector(JHhook_sendAction:to:forEvent:), method_getImplementation(JH_sendAction), method_getTypeEncoding(JH_sendAction));
method_setImplementation(JH_sendAction, class_getMethodImplementation([self class], @selector(JHhook_sendAction:to:forEvent:)));
}
/**
替换的方法
*/
-(void)JHhook_sendAction:(SEL)action to:(nullable id)target forEvent:(nullable UIEvent *)event{
NSString *methodName = NSStringFromSelector(action);
NSString *className = [NSString stringWithUTF8String: object_getClassName(target)];
UIControl *sender = (UIControl *)self;
//第一层,视图ClassName
NSDictionary *data = [[JHAnalyseControlAnalyseNode class]getJsonData];
if ([[data allKeys]containsObject:className]) {
//第二层,Action
NSDictionary *class = data[className];
if([[class allKeys]containsObject:methodName]){
NSDictionary *action = class[methodName];
NSString *tag = [NSString stringWithFormat:@"%ld",sender.tag];
if([[action allKeys]containsObject:tag]){
NSDictionary *oneAction = action[tag];
NSLog(@"mtthodName=%@,className=%@,classRealName=%@tag=%@",methodName,className,oneAction[@"name"],tag);
//使用当前时间表示最后操作时间
NSDate *date = [NSDate date];
NSTimeZone *zone = [NSTimeZone systemTimeZone];
NSInteger interval = [zone secondsFromGMTForDate: date];
NSDate *localeDate = [date dateByAddingTimeInterval: interval];
//组合数据并存入数据库
NSDictionary *eventDic = @{@"eventClass":className,
@"eventCodeName":methodName,
@"eventCount":@"1",
@"eventDate":[NSString stringWithFormat:@"%@",localeDate],
@"eventName":oneAction[@"name"],
@"eventTag":tag,
@"eventUser":@"jianghong",
};
[JH_AnalyseDataHelper _AnalyseWithData:eventDic withType:AnalyseTypeEvent];
}
}
}
[self JHhook_sendAction:action to:target forEvent:event];
}
+(NSDictionary *)getJsonData{
NSString *filePath = [[NSBundle mainBundle]pathForResource:@"analyse" ofType:@"json"];
NSData *jsonData = [NSData dataWithContentsOfFile:filePath];
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableLeaves error:nil];
return dic[@"event"];
}
配置的json文件(这个json文件最终将会配置到服务端作为下载数据)
{
"viewController":{
"JHChatBaseController":"聊天主页面",
"JHMapLocationVC":"定位",
"JHChildMessageVC":"消息",
"JHChildFriendsVC":"好友",
"JHNoteVC":"广场",
"JHSquareVC":"笔记"
},
"event":{
"JHInputView":{
"_additionButtonAction:":{
"0":{
"class":"JHInputView",
"event":"_additionButtonAction:",
"tag":"0",
"name":"录音"
},
"1":{
"class":"JHInputView",
"event":"_additionButtonAction:",
"tag":"1",
"name":"相册"
},
"2":{
"class":"JHInputView",
"event":"_additionButtonAction:",
"tag":"2",
"name":"相机"
},
"3":{
"class":"JHInputView",
"event":"_additionButtonAction:",
"tag":"3",
"name":"定位"
}
},
"_sendAction":{
"0":{
"class":"JHInputView",
"event":"_sendAction",
"tag":"0",
"name":"发送信息"
}
}
},
"JHChatBaseCellVoice":{
"onPlayButton:":{
"0":{
"class":"JHChatBaseCellVoice",
"event":"onPlayButton:",
"tag":"0",
"name":"播放录音"
}
}
}
}
}
CoreData数据库操作
1.建立CoreDataModel对象
2.根据统计类型查询数据库更新数据库
#import "JH_AnalyseDataHelper.h"
#define kManagedObjectContext [JH_ChatMessageManager sharedInstance].managedObjectContext
#define JH_EventAnalyseData @"EventAnalyseData"
#define JH_ViewControllerAnalyseData @"ViewControllerAnalyseData"
@implementation JH_AnalyseDataHelper
+(void)_AnalyseWithData:(NSDictionary *)data withType:(AnalyseType )analyseType{
if (analyseType==AnalyseTypeViewController) {
[self analyseVCWithData:data];
}else if (analyseType == AnalyseTypeEvent){
[self analyseEventWithData:data];
}
}
/**
分析统计页面
*/
+(void)analyseVCWithData:(NSDictionary *)data{
//判断是新建还是更新
NSArray *list = [self _searchViewControllerData];
//创建对应的类
NSString *vcName = data[@"viewControllerName"];
for (ViewControllerAnalyseData *vcModel in list) {
if ([vcModel.viewControllerName isEqualToString:vcName]) {
//更新时长数据
vcModel.viewControllerTime = vcModel.viewControllerTime + [data[@"viewControllerTime"] floatValue];
[[JH_ChatMessageManager sharedInstance] saveContext]; //保存
return;
}
}
//创建一个新的
ViewControllerAnalyseData *vcModel = [NSEntityDescription insertNewObjectForEntityForName:JH_ViewControllerAnalyseData inManagedObjectContext:kManagedObjectContext];
for (NSString *str in [data allKeys]) {
if ([str isEqualToString:@"viewControllerTime"]) {
float time = [data[str] floatValue];
[vcModel setValue:@(time) forKey:str];
continue;
}
[vcModel setValue:data[str] forKey:str];
}
[[JH_ChatMessageManager sharedInstance] saveContext]; //保存
}
/**
分析统计事件
*/
+(void)analyseEventWithData:(NSDictionary *)data{
//判断是新建还是更新
NSArray *list = [self _searchEventData];
//创建对应的类
NSString *eventName = data[@"eventName"];
for (EventAnalyseData *vcModel in list) {
if ([vcModel.eventName isEqualToString:eventName]) {
//更新点击次数数据
vcModel.eventCount = vcModel.eventCount + [data[@"eventCount"] integerValue];
[[JH_ChatMessageManager sharedInstance] saveContext]; //保存
return;
}
}
//创建一个新的
EventAnalyseData *eventModel = [NSEntityDescription insertNewObjectForEntityForName:JH_EventAnalyseData inManagedObjectContext:kManagedObjectContext];
for (NSString *str in [data allKeys]) {
if ([str isEqualToString:@"eventCount"]) {
NSInteger count = [data[str] integerValue];
[eventModel setValue:@(count) forKey:str];
continue;
}
[eventModel setValue:data[str] forKey:str];
}
[[JH_ChatMessageManager sharedInstance] saveContext]; //保存
}
#pragma mark - 查询数据(暂时使用全部搜索)
+(NSArray *)_searchViewControllerData{
/**
数据查询数据(全部)
*/
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:JH_ViewControllerAnalyseData
inManagedObjectContext:kManagedObjectContext];
[request setEntity:entity];
NSError *error = nil;
NSArray *objectResults = [kManagedObjectContext
executeFetchRequest:request
error:&error];
return objectResults;
}
+(NSArray *)_searchEventData{
/**
数据查询数据(全部)
*/
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:JH_EventAnalyseData
inManagedObjectContext:kManagedObjectContext];
[request setEntity:entity];
NSError *error = nil;
NSArray *objectResults = [kManagedObjectContext
executeFetchRequest:request
error:&error];
return objectResults;
}