『ios』無(wú)痕埋點(diǎn)探索 (頁(yè)面顯示 UIButton UIGestureRecognizer)

這是一篇無(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)钾腺。


image.png

對(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ì)名字的唯一性邮府。直接用名字也可以。


image.png
"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)的更快加勤。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末仙辟,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子鳄梅,更是在濱河造成了極大的恐慌叠国,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,294評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件戴尸,死亡現(xiàn)場(chǎng)離奇詭異粟焊,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,493評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門项棠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)悲雳,“玉大人,你說(shuō)我怎么就攤上這事香追『掀埃” “怎么了?”我有些...
    開封第一講書人閱讀 157,790評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵透典,是天一觀的道長(zhǎng)晴楔。 經(jīng)常有香客問(wèn)我,道長(zhǎng)峭咒,這世上最難降的妖魔是什么婆芦? 我笑而不...
    開封第一講書人閱讀 56,595評(píng)論 1 284
  • 正文 為了忘掉前任绒极,我火速辦了婚禮羹幸,結(jié)果婚禮上勇吊,老公的妹妹穿的比我還像新娘。我一直安慰自己顽决,他們只是感情好短条,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,718評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著才菠,像睡著了一般茸时。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赋访,一...
    開封第一講書人閱讀 49,906評(píng)論 1 290
  • 那天可都,我揣著相機(jī)與錄音,去河邊找鬼蚓耽。 笑死渠牲,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的步悠。 我是一名探鬼主播签杈,決...
    沈念sama閱讀 39,053評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼鼎兽!你這毒婦竟也來(lái)了答姥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,797評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤谚咬,失蹤者是張志新(化名)和其女友劉穎鹦付,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體择卦,經(jīng)...
    沈念sama閱讀 44,250評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡敲长,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,570評(píng)論 2 327
  • 正文 我和宋清朗相戀三年郎嫁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祈噪。...
    茶點(diǎn)故事閱讀 38,711評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡行剂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出钳降,到底是詐尸還是另有隱情,我是刑警寧澤腌巾,帶...
    沈念sama閱讀 34,388評(píng)論 4 332
  • 正文 年R本政府宣布遂填,位于F島的核電站,受9級(jí)特大地震影響澈蝙,放射性物質(zhì)發(fā)生泄漏吓坚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,018評(píng)論 3 316
  • 文/蒙蒙 一灯荧、第九天 我趴在偏房一處隱蔽的房頂上張望礁击。 院中可真熱鬧,春花似錦逗载、人聲如沸哆窿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,796評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)挚躯。三九已至,卻和暖如春擦秽,著一層夾襖步出監(jiān)牢的瞬間码荔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,023評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工感挥, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缩搅,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,461評(píng)論 2 360
  • 正文 我出身青樓触幼,卻偏偏與公主長(zhǎng)得像硼瓣,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子置谦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,595評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容