項(xiàng)目中需要統(tǒng)計(jì)的數(shù)據(jù)包括
1.在某個(gè)頁(yè)面的停留時(shí)間(針對(duì)UIViewController)
2.某個(gè)事件(method)觸發(fā)的次數(shù)
3.某個(gè)View的展示次數(shù)
(目前屬于試驗(yàn)階段)
1.停留時(shí)間runtime swap viewDidAppear & viewDidDisAppear
#import "UIViewController+JHswizzling.h"
static NSDate *startDate;
@implementation UIViewController (JHswizzling)
+ (void)load{
// 通過(guò)class_getInstanceMethod()函數(shù)從當(dāng)前對(duì)象中的method list獲取method結(jié)構(gòu)體,如果是類(lèi)方法就使用class_getClassMethod()函數(shù)獲取。
Method fromMethod = class_getInstanceMethod([self class], @selector(viewDidAppear:));
Method toMethod = class_getInstanceMethod([self class], @selector(JH_swizzlingViewDidAppear));
/**
* 我們?cè)谶@里使用class_addMethod()函數(shù)對(duì)Method Swizzling做了一層驗(yàn)證,如果self沒(méi)有實(shí)現(xiàn)被交換的方法,會(huì)導(dǎo)致失敗。
* 而且self沒(méi)有交換的方法實(shí)現(xiàn),但是父類(lèi)有這個(gè)方法,這樣就會(huì)調(diào)用父類(lèi)的方法,結(jié)果就不是我們想要的結(jié)果了。
* 所以我們?cè)谶@里通過(guò)class_addMethod()的驗(yàn)證,如果self實(shí)現(xiàn)了這個(gè)方法,class_addMethod()函數(shù)將會(huì)返回NO,我們就可以對(duì)其進(jìn)行交換了。
*/
if (!class_addMethod([self class], @selector(JH_swizzlingViewDidAppear), method_getImplementation(toMethod), method_getTypeEncoding(toMethod))) {
method_exchangeImplementations(fromMethod, toMethod);
}
// 通過(guò)class_getInstanceMethod()函數(shù)從當(dāng)前對(duì)象中的method list獲取method結(jié)構(gòu)體,如果是類(lèi)方法就使用class_getClassMethod()函數(shù)獲取。
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);
}
}
// 我們自己實(shí)現(xiàn)的方法,也就是和self的viewDidAppear方法進(jìn)行交換的方法。
- (void)JH_swizzlingViewDidAppear{
NSString *str = [NSString stringWithFormat:@"%@", self.class];
// 我們?cè)谶@里加一個(gè)判斷,將系統(tǒng)的UIViewController的對(duì)象剔除掉
NSDictionary *data = [self getJsonData];
if ([[data allKeys]containsObject:str]) {
if(![str containsString:@"UI"]){
startDate = [NSDate date];
NSLog(@"統(tǒng)計(jì)打點(diǎn)出現(xiàn) : %@ time : %@", [self getJsonData][str] ,startDate);
}
}
[self JH_swizzlingViewDidAppear];
}
// 我們自己實(shí)現(xiàn)的方法,也就是和self的viewDidDisAppear方法進(jìn)行交換的方法。
- (void)JH_swizzlingViewDidDisAppear{
NSString *str = [NSString stringWithFormat:@"%@", self.class];
// 我們?cè)谶@里加一個(gè)判斷,將系統(tǒng)的UIViewController的對(duì)象剔除掉
NSDictionary *data = [self getJsonData];
if ([[data allKeys]containsObject:str]) {
if(![str containsString:@"UI"]){
//計(jì)算時(shí)間差
NSDate *endDate = [NSDate date];
NSTimeInterval duration = [endDate timeIntervalSinceDate:startDate];
NSLog(@"統(tǒng)計(jì)打點(diǎn)出現(xiàn) : %@ time : %f 時(shí)長(zhǎng)", data[str] ,duration);
//組合數(shù)據(jù)并存入數(shù)據(jù)庫(kù)
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.某個(gè)事件(method)觸發(fā)的次數(shù),針對(duì)系統(tǒng)控件
#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);
//使用當(dāng)前時(shí)間表示最后操作時(shí)間
NSDate *date = [NSDate date];
NSTimeZone *zone = [NSTimeZone systemTimeZone];
NSInteger interval = [zone secondsFromGMTForDate: date];
NSDate *localeDate = [date dateByAddingTimeInterval: interval];
//組合數(shù)據(jù)并存入數(shù)據(jù)庫(kù)
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文件(這個(gè)json文件最終將會(huì)配置到服務(wù)端作為下載數(shù)據(jù))
{
"viewController":{
"JHChatBaseController":"聊天主頁(yè)面",
"JHMapLocationVC":"定位",
"JHChildMessageVC":"消息",
"JHChildFriendsVC":"好友",
"JHNoteVC":"廣場(chǎng)",
"JHSquareVC":"筆記"
},
"event":{
"JHInputView":{
"_additionButtonAction:":{
"0":{
"class":"JHInputView",
"event":"_additionButtonAction:",
"tag":"0",
"name":"錄音"
},
"1":{
"class":"JHInputView",
"event":"_additionButtonAction:",
"tag":"1",
"name":"相冊(cè)"
},
"2":{
"class":"JHInputView",
"event":"_additionButtonAction:",
"tag":"2",
"name":"相機(jī)"
},
"3":{
"class":"JHInputView",
"event":"_additionButtonAction:",
"tag":"3",
"name":"定位"
}
},
"_sendAction":{
"0":{
"class":"JHInputView",
"event":"_sendAction",
"tag":"0",
"name":"發(fā)送信息"
}
}
},
"JHChatBaseCellVoice":{
"onPlayButton:":{
"0":{
"class":"JHChatBaseCellVoice",
"event":"onPlayButton:",
"tag":"0",
"name":"播放錄音"
}
}
}
}
}
CoreData數(shù)據(jù)庫(kù)操作
1.建立CoreDataModel對(duì)象


image.png
2.根據(jù)統(tǒng)計(jì)類(lèi)型查詢(xún)數(shù)據(jù)庫(kù)更新數(shù)據(jù)庫(kù)
#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];
}
}
/**
分析統(tǒng)計(jì)頁(yè)面
*/
+(void)analyseVCWithData:(NSDictionary *)data{
//判斷是新建還是更新
NSArray *list = [self _searchViewControllerData];
//創(chuàng)建對(duì)應(yīng)的類(lèi)
NSString *vcName = data[@"viewControllerName"];
for (ViewControllerAnalyseData *vcModel in list) {
if ([vcModel.viewControllerName isEqualToString:vcName]) {
//更新時(shí)長(zhǎng)數(shù)據(jù)
vcModel.viewControllerTime = vcModel.viewControllerTime + [data[@"viewControllerTime"] floatValue];
[[JH_ChatMessageManager sharedInstance] saveContext]; //保存
return;
}
}
//創(chuàng)建一個(gè)新的
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]; //保存
}
/**
分析統(tǒng)計(jì)事件
*/
+(void)analyseEventWithData:(NSDictionary *)data{
//判斷是新建還是更新
NSArray *list = [self _searchEventData];
//創(chuàng)建對(duì)應(yīng)的類(lèi)
NSString *eventName = data[@"eventName"];
for (EventAnalyseData *vcModel in list) {
if ([vcModel.eventName isEqualToString:eventName]) {
//更新點(diǎn)擊次數(shù)數(shù)據(jù)
vcModel.eventCount = vcModel.eventCount + [data[@"eventCount"] integerValue];
[[JH_ChatMessageManager sharedInstance] saveContext]; //保存
return;
}
}
//創(chuàng)建一個(gè)新的
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 - 查詢(xún)數(shù)據(jù)(暫時(shí)使用全部搜索)
+(NSArray *)_searchViewControllerData{
/**
數(shù)據(jù)查詢(xún)數(shù)據(jù)(全部)
*/
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{
/**
數(shù)據(jù)查詢(xún)數(shù)據(jù)(全部)
*/
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;
}