這是一篇無(wú)痕埋點(diǎn)方案的探索基括,學(xué)到的東西,怕忘記了财岔,所以記下來(lái)风皿,就這樣。
我們?cè)谄綍r(shí)的項(xiàng)目中匠璧,會(huì)用到埋點(diǎn)這個(gè)功能吧桐款,如果頁(yè)面很少,還好說(shuō)患朱,我們可以手動(dòng)進(jìn)行埋點(diǎn)鲁僚,如果是頁(yè)面變多炊苫,那么手動(dòng)埋點(diǎn)將會(huì)變得非常的浪費(fèi)時(shí)間和效率裁厅,所以無(wú)痕埋點(diǎn)就這樣誕生了冰沙。
講無(wú)痕埋點(diǎn)之前先放一個(gè)方法。
交換方法
+(void)swizzingForClass:(Class)cls originalSel:(SEL)originalSelector swizzingSel:(SEL)swizzingSelector
{
Class class = cls;
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzingMethod = class_getInstanceMethod(class, swizzingSelector);
BOOL addMethod = class_addMethod(class,
originalSelector,
method_getImplementation(swizzingMethod),
method_getTypeEncoding(swizzingMethod));
if (addMethod) {
class_replaceMethod(class,
swizzingSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
}else{
method_exchangeImplementations(originalMethod, swizzingMethod);
}
}
因?yàn)槁顸c(diǎn)的精髓部分在于對(duì)數(shù)據(jù)的處理执虹,所以別急拓挥,繼續(xù)往下看。
對(duì)于頁(yè)面顯示隱藏方面的埋點(diǎn)該怎么做呢袋励?沒(méi)錯(cuò)就是對(duì)viewWillAppear viewWillDisappear viewDidLoad進(jìn)行交換侥啤,然后監(jiān)聽。
+(void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL originalAppearSelector = @selector(viewWillAppear:);
SEL swizzingAppearSelector = @selector(user_viewWillAppear:);
[MethodSwizzingTool swizzingForClass:[self class] originalSel:originalAppearSelector swizzingSel:swizzingAppearSelector];
SEL originalDisappearSelector = @selector(viewWillDisappear:);
SEL swizzingDisappearSelector = @selector(user_viewWillDisappear:);
[MethodSwizzingTool swizzingForClass:[self class] originalSel:originalDisappearSelector swizzingSel:swizzingDisappearSelector];
SEL originalDidLoadSelector = @selector(viewDidLoad);
SEL swizzingDidLoadSelector = @selector(user_viewDidLoad);
[MethodSwizzingTool swizzingForClass:[self class] originalSel:originalDidLoadSelector swizzingSel:swizzingDidLoadSelector];
});
}
那對(duì)于按鈕的點(diǎn)擊監(jiān)聽呢茬故?別忘了這個(gè)方法sendAction:to:forEvent:盖灸。
SEL originalSelector = @selector(sendAction:to:forEvent:);
SEL swizzingSelector = @selector(user_sendAction:to:forEvent:);
[MethodSwizzingTool swizzingForClass:[self class] originalSel:originalSelector swizzingSel:swizzingSelector];
那如何定位到到點(diǎn)擊了哪個(gè)btn呢?先看數(shù)據(jù)結(jié)構(gòu)吧
"ACTION": {
"ViewController/jumpSecond/0": {
"userDefined": {
"eventid": "201803074|93",
"target": "",
"pageid": "234",
"pagename": "button點(diǎn)擊磺芭,跳轉(zhuǎn)至下一個(gè)頁(yè)面"
},
"pagePara": {
"testKey9": {
"propertyName": "testPara",
"propertyPath":"",
"containIn": "0"
}
}
},
"SecondViewController/back": {
"userDefined": {
"eventid": "201803074|965",
"target": "second",
"pageid": "234",
"pagename": "button點(diǎn)擊赁炎,返回"
},
"pagePara": {
"testKey9": {
"propertyName": "testPara",
"propertyPath":"",
"containIn": "0"
}
}
}
},
再來(lái)看監(jiān)聽的事件
-(void)user_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
{
[self user_sendAction:action to:target forEvent:event];
NSString * identifier = [NSString stringWithFormat:@"%@/%@/%ld", [target class], NSStringFromSelector(action),self.tag];
NSDictionary * dic = [[[DataContainer dataInstance].data objectForKey:@"ACTION"] objectForKey:identifier];
if (dic) {
NSString * eventid = dic[@"userDefined"][@"eventid"];
NSString * targetname = dic[@"userDefined"][@"target"];
NSString * pageid = dic[@"userDefined"][@"pageid"];
NSString * pagename = dic[@"userDefined"][@"pagename"];
NSDictionary * pagePara = dic[@"pagePara"];
__block NSMutableDictionary * uploadDic = [NSMutableDictionary dictionaryWithCapacity:0];
[pagePara enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
id value = [CaptureTool captureVarforInstance:target withPara:obj];
if (value && key) {
[uploadDic setObject:value forKey:key];
}
}];
NSLog(@"\n event id === %@,\n target === %@, \n pageid === %@,\n pagename === %@,\n pagepara === %@ \n", eventid, targetname, pageid, pagename, uploadDic);
}
}
可以看到identifier @"ViewController/jumpSecond/0"
我們根據(jù)當(dāng)前所在的類 跳轉(zhuǎn)的方法 按鈕的tag 來(lái)找到那個(gè)btn,進(jìn)行進(jìn)行打點(diǎn)钾腺。
對(duì)于手勢(shì)的監(jiān)聽呢徙垫?這個(gè)跟btn這些就不太一樣了。這個(gè)需要監(jiān)聽設(shè)置代理的方法放棒。initWithTarget:action:
+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[MethodSwizzingTool swizzingForClass:[self class] originalSel:@selector(initWithTarget:action:) swizzingSel:@selector(vi_initWithTarget:action:)];
});
}
然后添加關(guān)于sel_ SEL "UIDimmingView/handleSingleTap:" 的方法實(shí)現(xiàn)responseUser_gesture姻报,具體UIDimmingView是什么可以自行打印查看。然后與handleSingleTap進(jìn)行方法交換间螟。
- (instancetype)vi_initWithTarget:(nullable id)target action:(nullable SEL)action
{
UIGestureRecognizer *selfGestureRecognizer = [self vi_initWithTarget:target action:action];
if (!target && !action) {
return selfGestureRecognizer;
}
if ([target isKindOfClass:[UIScrollView class]]) {
return selfGestureRecognizer;
}
Class class = [target class];
SEL sel = action;
NSString * sel_name = [NSString stringWithFormat:@"%s/%@", class_getName([target class]),NSStringFromSelector(action)];
SEL sel_ = NSSelectorFromString(sel_name);
BOOL isAddMethod = class_addMethod(class,
sel_,
method_getImplementation(class_getInstanceMethod([self class], @selector(responseUser_gesture:))),
nil);
//看到這里別疑惑吴旋,這里是我們給UIGestureRecognizer添加的屬性。
self.methodName = NSStringFromSelector(action);
if (isAddMethod) {
Method selMethod = class_getInstanceMethod(class, sel);
Method sel_Method = class_getInstanceMethod(class, sel_);
method_exchangeImplementations(selMethod, sel_Method);
}
return selfGestureRecognizer;
}
然后我們可以實(shí)現(xiàn)responseUser_gesture
-(void)responseUser_gesture:(UIGestureRecognizer *)gesture
{
NSString * identifier = [NSString stringWithFormat:@"%s/%@", class_getName([self class]),gesture.methodName];
SEL sel = NSSelectorFromString(identifier);
if ([self respondsToSelector:sel]) {
IMP imp = [self methodForSelector:sel];
void (*func)(id, SEL,id) = (void *)imp;
func(self, sel,gesture);
}
NSDictionary * dic = [[[DataContainer dataInstance].data objectForKey:@"GESTURE"] objectForKey:identifier];
if (dic) {
NSString * eventid = dic[@"userDefined"][@"eventid"];
NSString * targetname = dic[@"userDefined"][@"target"];
NSString * pageid = dic[@"userDefined"][@"pageid"];
NSString * pagename = dic[@"userDefined"][@"pagename"];
NSDictionary * pagePara = dic[@"pagePara"];
__block NSMutableDictionary * uploadDic = [NSMutableDictionary dictionaryWithCapacity:0];
[pagePara enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
id value = [CaptureTool captureVarforInstance:self withPara:obj];
if (value && key) {
[uploadDic setObject:value forKey:key];
}
}];
NSLog(@"\n event id === %@,\n target === %@, \n pageid === %@,\n pagename === %@,\n pagepara === %@ \n", eventid, targetname, pageid, pagename, uploadDic);
}
}
我們可以根據(jù)手勢(shì)所在的類名和方法來(lái)確定這是哪一個(gè)手勢(shì)寒亥。當(dāng)然如果你可以保證手勢(shì)名字的唯一性邮府。直接用名字也可以。
"GESTURE": {
"ViewController/gesture1clicked:":{
"userDefined": {
"eventid": "201803074|93",
"target": "",
"pageid": "手勢(shì)1對(duì)應(yīng)的id",
"pagename": "手勢(shì)1對(duì)應(yīng)的page name"
},
"pagePara": {
"testKey1": {
"propertyName": "testPara",
"propertyPath":"",
"containIn": "0"
}
}
},
"ViewController/gesture2clicked:":{
"userDefined": {
"eventid": "201803074|93",
"target": "",
"pageid": "手勢(shì)2對(duì)應(yīng)的id",
"pagename": "手勢(shì)2對(duì)應(yīng)的page name"
},
"pagePara": {
"testKey2": {
"propertyName": "testPara",
"propertyPath":"",
"containIn": "0"
}
}
},
"SecondViewController/gesture3clicked:":{
"userDefined": {
"eventid": "201803074|98",
"target": "",
"pageid": "gesture3clicked",
"pagename": "手勢(shì)3對(duì)應(yīng)的page name"
},
"pagePara": {
"user_age": {
}
}
}
}
對(duì)于埋點(diǎn)配置參數(shù)方面內(nèi)容溉奕,另開一篇來(lái)說(shuō)褂傀。因?yàn)檫€涉及到tableView和collectionView.
站在巨人的肩膀上才能看的更遠(yuǎn),不斷學(xué)習(xí)才能成長(zhǎng)的更快加勤。